OXYGENHUB
◆ main openmsx / src / cpu / CPUCore.cc
153.8 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
// MEMORY EMULATION
2
// ----------------
3
//
4
// Memory access emulation is a very important part of the CPU emulation.
5
// Because they happen so frequently they really need to be executed as fast as
6
// possible otherwise they will completely bring down the speed of the CPU
7
// emulation.
8
//
9
// A very fast way to emulate memory accesses is by simply reading/writing to a
10
// 64kb array (for a 16-bit address space). Unfortunately this doesn't allow
11
// for memory mapped IO (MMIO). These are memory regions where read/writes
12
// trigger side effects, so where we need to execute device-specific code on
13
// read or writes. An alternative that does work with MMIO is for every access
14
// execute a virtual method call, (this is the approach taken by most current
15
// MSX emulators). Unfortunately this is also a lot slower.
16
//
17
// It is possible to combine the speed of array accesses with the flexibility
18
// of virtual methods. In openMSX it's implemented as follows: the 64kb address
19
// space is divided in 256 regions of 256 bytes (called cacheLines in the code
20
// below). For each such region we store a pointer, if this pointer is nullptr
21
// then we have to use the slow way (=virtual method call). If it is not nullptr,
22
// the pointer points to a block of memory that can be directly accessed. In
23
// some contexts accesses via the pointer are known as backdoor accesses while
24
// the accesses directly to the device are known as front-door accesses.
25
//
26
// We keep different pointers for read and write accesses. This allows to also
27
// implement ROMs efficiently: read is handled as regular RAM, but writes end
28
// up in some dummy memory region. This region is called 'unmappedWrite' in the
29
// code. There is also a special region 'unmappedRead', this region is filled
30
// with 0xFF and can be used to model (parts of) a device that don't react to
31
// reads (so reads return 0xFF).
32
//
33
// Because of bank switching (the MSX slot select mechanism, but also e.g.
34
// MegaROM back switching) the memory map as seen by the Z80 is not static. This
35
// means that the cacheLine pointers also need to change during runtime. To
36
// solve this we made the bank switch code also responsible for invalidating the
37
// cacheLines of the switched region. These pointers are filled-in again in a
38
// lazy way: the first read or write to a cache line will first get this
39
// pointer (see getReadCacheLine() and getWriteCacheLine() in the code below),
40
// from then on this pointer is used for all further accesses to this region,
41
// until the cache is invalidated again.
42
//
43
//
44
// INSTRUCTION EMULATION
45
// ---------------------
46
//
47
// UPDATE: the 'threaded interpreter model' is not enabled by default
48
//         main reason is the huge memory requirement while compiling
49
//         and that it doesn't work on non-gcc compilers
50
//
51
// The current implementation is based on a 'threaded interpreter model'. In
52
// the text below I'll call the older implementation the 'traditional
53
// interpreter model'. From a very high level these two models look like this:
54
//
55
//     Traditional model:
56
//         while (!needExit()) {
57
//             uint8_t opcode = fetch(PC++);
58
//             switch (opcode) {
59
//                 case 0x00: nop(); break;
60
//                 case 0x01: ld_bc_nn(); break;
61
//                 ...
62
//             }
63
//         }
64
//
65
//     Threaded model:
66
//         uint8_t opcode = fetch(PC++);   //
67
//         goto *(table[opcode]);       // fetch-and-dispatch
68
//         // note: the goto * syntax is a gcc extension called computed-gotos
69
//
70
//         op00: nop();      if (!needExit()) [fetch-and-dispatch];
71
//         op01: ld_bc_nn(); if (!needExit()) [fetch-and-dispatch];
72
//         ...
73
//
74
// In the first model there is a central place in the code that fetches (the
75
// first byte of) the instruction and based on this byte jumps to the
76
// appropriate routine. In the second model, this fetch-and-dispatch logic is
77
// duplicated at the end of each instruction.
78
//
79
// Typically the 'dispatch' part in above paragraph is implemented (either by
80
// the compiler or manually using computed goto's) via a jump table. Thus on
81
// assembler level via an indirect jump. For the host CPU it's hard to predict
82
// the destination address of such an indirect jump, certainly if there's only
83
// one such jump for all dispatching (the traditional model). If each
84
// instruction has its own indirect jump instruction (the threaded model), it
85
// becomes a bit easier, because often one particular z80 instructions is
86
// followed by a specific other z80 instruction (or one from a small subset).
87
// For example a z80 'cp' instruction is most likely followed by a 'conditional
88
// jump' z80 instruction. Modern CPUs are quite sensitive to
89
// branch-(mis)predictions, so the above optimization helps quite a lot. I
90
// measured a speedup of more than 10%!
91
//
92
// There is another advantage to the threaded model. Because also the
93
// needExit() test is duplicated for each instruction, it becomes possible to
94
// tweak it for individual instructions. But first let me explain this
95
// exit-test in more detail.
96
//
97
// These are the main reasons why the emulator should stop emulating CPU
98
// instructions:
99
//  1) When other devices than the CPU must be emulated (e.g. video frame
100
//     rendering). In openMSX this is handled by the Scheduler class and
101
//     actually we don't exit the CPU loop (anymore) for this. Instead we
102
//     simply execute the device code as a subroutine. Each time right before
103
//     we access an IO port or do a front-door memory access, there is a check
104
//     whether we should emulate device code (search for schedule() in the code
105
//     below).
106
//  2) To keep the inner CPU loop as fast as possible we don't check for IRQ,
107
//     NMI or HALT status in this loop. Instead this condition is checked only
108
//     once at the beginning outside of the loop (if there wasn't a pending IRQ
109
//     on the first instruction there also won't be one on the second
110
//     instruction, if all we did was emulating cpu instructions). Now when one
111
//     of these conditions changes, we must exit the inner loop and re-evaluate
112
//     them. For example after an EI instruction we must check the IRQ status
113
//     again.
114
//  3) Various reasons like:
115
//      * Z80/R800 switch
116
//      * executing a Tcl command (could be a cpu-register debug read)
117
//      * exit the emulator
118
//  4) 'once-in-a-while': To avoid threading problems and race conditions,
119
//     several threads in openMSX only 'schedule' work that will later be
120
//     executed by the main emulation thread. The main thread checks for such
121
//     task outside of the cpu emulation loop. So once-in-a-while we need to
122
//     exit the loop. The exact timing doesn't matter here because anyway the
123
//     relative timing between threads is undefined.
124
// So for 1) we don't need to do anything (we don't actually exit). For 2) and
125
// 3) we need to exit the loop as soon as possible (right after the current
126
// instruction is finished). For 4) it's OK to exit 'eventually' (a few hundred
127
// z80 instructions late is still OK).
128
//
129
// Condition 2) is implemented with the 'slowInstructions' mechanism. Condition
130
// 3) via exitCPULoopSync() (may only get called by the main emulation thread)
131
// and condition 4) is implemented via exitCPULoopAsync() (can be called from
132
// any thread).
133
//
134
// Now back to the exit-test optimization: in the threaded model each
135
// instruction ends with:
136
//
137
//     if (needExit()) return
138
//     uint8_t opcode = fetch(PC++);
139
//     goto *(table[opcode]);
140
//
141
// And if we look in more detail at fetch():
142
//
143
//     if (canDoBackdoor(addr)) {
144
//         doBackdoorAccess(addr);
145
//     } else {
146
//         doFrontdoorAccess(addr);
147
//     }
148
//
149
// So there are in fact two checks per instruction. This can be reduced to only
150
// one check with the following trick:
151
//
152
// !!!WRONG!!!
153
// In the past we optimized this to only check canDoBackdoor() (and make sure
154
// canDoBackdoor() returned false when needExit() would return true). This
155
// worked rather well, except for one case: when we exit the CPU loop we also
156
// check for pending Syncronization points. It is possible such a SyncPoint
157
// raises the IRQ line. So it is important to check for exit after every
158
// instruction, otherwise we would enter the IRQ routine a couple of
159
// instructions too late.
160
161
#include "CPUCore.hh"
162
163
#include "Dasm.hh"
164
#include "MSXCPUInterface.hh"
165
#include "R800.hh"
166
#include "Z80.hh"
167
168
#include "MSXCliComm.hh"
169
#include "MSXMotherBoard.hh"
170
#include "Scheduler.hh"
171
#include "TclCallback.hh"
172
#include "Thread.hh"
173
174
#include "endian.hh"
175
#include "inline.hh"
176
#include "narrow.hh"
177
#include "unreachable.hh"
178
#include "xrange.hh"
179
180
#include <array>
181
#include <bit>
182
#include <cassert>
183
#include <iostream>
184
#include <type_traits>
185
186
187
//
188
// #define USE_COMPUTED_GOTO
189
//
190
// Computed goto's are not enabled by default:
191
// - Computed goto's are a gcc extension, it's not part of the official c++
192
//   standard. So this will only work if you use gcc as your compiler (it
193
//   won't work with visual c++ for example)
194
// - This is only beneficial on CPUs with branch prediction for indirect jumps
195
//   and a reasonable amount of cache. For example it is very beneficial for a
196
//   intel core2 cpu (10% faster), but not for a ARM920 (a few percent slower)
197
// - Compiling src/cpu/CPUCore.cc with computed goto's enabled is very demanding
198
//   on the compiler. On older gcc versions it requires up to 1.5GB of memory.
199
//   But even on more recent gcc versions it still requires around 700MB.
200
//
201
// Probably the easiest way to enable this, is to pass the -DUSE_COMPUTED_GOTO
202
// flag to the compiler. This is for example done in the super-opt flavour.
203
// See build/flavour-super-opt.mk
204
205
#ifndef _MSC_VER
206
  // [[maybe_unused]] on a label is not (yet?) officially part of c++
207
  // Gcc/clang do support it (as an extension), but visual studio complains
208
  // about it. Hence the different implementation for both.
209
  #define MAYBE_UNUSED_LABEL [[maybe_unused]]
210
#else
211
  #pragma warning(disable : 4102) // unreferenced label
212
  #define MAYBE_UNUSED_LABEL
213
#endif
214
215
216
namespace openmsx {
217
218
enum Reg8  : uint8_t { A, F, B, C, D, E, H, L, IXH, IXL, IYH, IYL, REG_I, REG_R, DUMMY };
219
enum Reg16 : uint8_t { AF, BC, DE, HL, IX, IY, SP };
220
221
// flag positions
222
static constexpr uint8_t S_FLAG = 0x80;
223
static constexpr uint8_t Z_FLAG = 0x40;
224
static constexpr uint8_t Y_FLAG = 0x20;
225
static constexpr uint8_t H_FLAG = 0x10;
226
static constexpr uint8_t X_FLAG = 0x08;
227
static constexpr uint8_t V_FLAG = 0x04;
228
static constexpr uint8_t P_FLAG = V_FLAG;
229
static constexpr uint8_t N_FLAG = 0x02;
230
static constexpr uint8_t C_FLAG = 0x01;
231
232
// flag-register lookup tables
233
struct Table {
234
	std::array<uint8_t, 256> ZS;
235
	std::array<uint8_t, 256> ZSXY;
236
	std::array<uint8_t, 256> ZSP;
237
	std::array<uint8_t, 256> ZSPXY;
238
	std::array<uint8_t, 256> ZSPH;
239
};
240
241
static constexpr uint8_t ZS0     = Z_FLAG;
242
static constexpr uint8_t ZSXY0   = Z_FLAG;
243
static constexpr uint8_t ZSP0    = Z_FLAG | V_FLAG;
244
static constexpr uint8_t ZSPXY0  = Z_FLAG | V_FLAG;
245
static constexpr uint8_t ZS255   = S_FLAG;
246
static constexpr uint8_t ZSXY255 = S_FLAG | X_FLAG | Y_FLAG;
247
248
static constexpr Table initTables()
249
{
250
	Table table = {};
251
252
	for (auto i_ : xrange(256)) {
253
		auto i = narrow_cast<uint8_t>(i_);
254
		uint8_t zFlag = (i == 0) ? Z_FLAG : 0;
255
		uint8_t sFlag = i & S_FLAG;
256
		uint8_t xFlag = i & X_FLAG;
257
		uint8_t yFlag = i & Y_FLAG;
258
		uint8_t vFlag = std::popcount(i) % 2 ? 0 : V_FLAG;
259
		table.ZS   [i] = zFlag | sFlag;
260
		table.ZSXY [i] = zFlag | sFlag | xFlag | yFlag;
261
		table.ZSP  [i] = zFlag | sFlag |                 vFlag;
262
		table.ZSPXY[i] = zFlag | sFlag | xFlag | yFlag | vFlag;
263
		table.ZSPH [i] = zFlag | sFlag |                 vFlag | H_FLAG;
264
	}
265
	assert(table.ZS   [  0] == ZS0);
266
	assert(table.ZSXY [  0] == ZSXY0);
267
	assert(table.ZSP  [  0] == ZSP0);
268
	assert(table.ZSPXY[  0] == ZSPXY0);
269
	assert(table.ZS   [255] == ZS255);
270
	assert(table.ZSXY [255] == ZSXY255);
271
272
	return table;
273
}
274
275
static constexpr Table table = initTables();
276
277
// conditions
278
struct CondC  { bool operator()(uint8_t f) const { return  (f & C_FLAG) != 0; } };
279
struct CondNC { bool operator()(uint8_t f) const { return !(f & C_FLAG); } };
280
struct CondZ  { bool operator()(uint8_t f) const { return  (f & Z_FLAG) != 0; } };
281
struct CondNZ { bool operator()(uint8_t f) const { return !(f & Z_FLAG); } };
282
struct CondM  { bool operator()(uint8_t f) const { return  (f & S_FLAG) != 0; } };
283
struct CondP  { bool operator()(uint8_t f) const { return !(f & S_FLAG); } };
284
struct CondPE { bool operator()(uint8_t f) const { return  (f & V_FLAG) != 0; } };
285
struct CondPO { bool operator()(uint8_t f) const { return !(f & V_FLAG); } };
286
struct CondTrue { bool operator()(uint8_t /*f*/) const { return true; } };
287
288
template<typename T> CPUCore<T>::CPUCore(
289
		MSXMotherBoard& motherboard_, const std::string& name,
290
		TclCallback& diHaltCallback_, EmuTime time)
291
	: CPURegs(T::IS_R800)
292
	, T(time, motherboard_.getScheduler())
293
	, motherboard(motherboard_)
294
	, scheduler(motherboard.getScheduler())
295
	, diHaltCallback(diHaltCallback_)
296
	, IRQStatus(motherboard.getDebugger(), name + ".pendingIRQ",
297
	            "Non-zero if there are pending IRQs (thus CPU would enter "
298
	            "interrupt routine in EI mode).",
299
	            0)
300
	, IRQAccept(motherboard.getDebugger(), name + ".acceptIRQ",
301
	            "This is a valueless (void) probe, it generates an event when the CPU accepts an IRQ.")
302
	, freqLocked(
303
		motherboard.getCommandController(), tmpStrCat(name, "_freq_locked"),
304
	        "real (locked) or custom (unlocked) CPU frequency",
305
	        true, Setting::Save::NO)
306
	, freqValue(
307
		motherboard.getCommandController(), tmpStrCat(name, "_freq"),
308
		"custom CPU frequency (only valid when unlocked)",
309
		T::CLOCK_FREQ, 1000000, 1000000000)
310
	, freq(T::CLOCK_FREQ)
311
	, isCMOS(motherboard.hasToshibaEngine())  // Toshiba MSX-ENGINEs embed a CMOS Z80
312
{
313
	static_assert(!std::is_polymorphic_v<CPUCore<T>>,
314
		"keep CPUCore non-virtual to keep PC at offset 0");
315
	doSetFreq();
316
	doReset(time);
317
}
318
319
template<typename T> void CPUCore<T>::warp(EmuTime time)
320
{
321
	assert(T::getTimeFast() <= time);
322
	T::setTime(time);
323
}
324
325
template<typename T> EmuTime CPUCore<T>::getCurrentTime() const
326
{
327
	return T::getTime();
328
}
329
330
template<typename T> void CPUCore<T>::doReset(EmuTime time)
331
{
332
	// AF and SP are 0xFFFF
333
	// PC, R, IFF1, IFF2, HALT and IM are 0x0
334
	// all others are random
335
	setAF(0xFFFF);
336
	setBC(0xFFFF);
337
	setDE(0xFFFF);
338
	setHL(0xFFFF);
339
	setIX(0xFFFF);
340
	setIY(0xFFFF);
341
	setPC(0x0000);
342
	setSP(0xFFFF);
343
	setAF2(0xFFFF);
344
	setBC2(0xFFFF);
345
	setDE2(0xFFFF);
346
	setHL2(0xFFFF);
347
	setIFF1(false);
348
	setIFF2(false);
349
	setHALT(false);
350
	setExtHALT(false);
351
	setIM(0);
352
	setI(0x00);
353
	setR(0x00);
354
	T::setMemPtr(0xFFFF);
355
	clearPrevious();
356
357
	// We expect this assert to be valid
358
	//   assert(T::getTimeFast() <= time); // time shouldn't go backwards
359
	// But it's disabled for the following reason:
360
	//   'motion' (IRC nickname) managed to create a replay file that
361
	//   contains a reset command that falls in the middle of a Z80
362
	//   instruction. Replayed commands go via the Scheduler, and are
363
	//   (typically) executed right after a complete CPU instruction. So
364
	//   the CPU is (slightly) ahead in time of the about to be executed
365
	//   reset command.
366
	//   Normally this situation should never occur: console commands,
367
	//   hotkeys, commands over cliComm, ... are all handled via the global
368
	//   event mechanism. Such global events are scheduled between CPU
369
	//   instructions, so also in a replay they should fall between CPU
370
	//   instructions.
371
	//   However if for some reason the timing of the emulation changed
372
	//   (improved emulation accuracy or a bug so that emulation isn't
373
	//   deterministic or the replay file was edited, ...), then the above
374
	//   reasoning no longer holds and the assert can trigger.
375
	// We need to be robust against loading older replays (when emulation
376
	// timing has changed). So in that respect disabling the assert is
377
	// good. Though in the example above (motion's replay) it's not clear
378
	// whether the assert is really triggered by mixing an old replay
379
	// with a newer openMSX version. In any case so far we haven't been
380
	// able to reproduce this assert by recording and replaying using a
381
	// single openMSX version.
382
	T::setTime(time);
383
384
	assert(NMIStatus == 0); // other devices must reset their NMI source
385
	assert(IRQStatus == 0); // other devices must reset their IRQ source
386
}
387
388
// I believe the following two methods are thread safe even without any
389
// locking. The worst that can happen is that we occasionally needlessly
390
// exit the CPU loop, but that's harmless
391
//  TODO thread issues are always tricky, can someone confirm this really
392
//       is thread safe
393
template<typename T> void CPUCore<T>::exitCPULoopAsync()
394
{
395
	// can get called from non-main threads
396
	exitLoop = true;
397
}
398
template<typename T> void CPUCore<T>::exitCPULoopSync()
399
{
400
	assert(Thread::isMainThread());
401
	exitLoop = true;
402
	T::disableLimit();
403
}
404
template<typename T> inline bool CPUCore<T>::needExitCPULoop()
405
{
406
	// always executed in main thread
407
	if (exitLoop) [[unlikely]] {
408
		// Note: The test-and-set is _not_ atomic! But that's fine.
409
		//   An atomic implementation is trivial (see below), but
410
		//   this version (at least on x86) avoids the more expensive
411
		//   instructions on the likely path.
412
		exitLoop = false;
413
		return true;
414
	}
415
	return false;
416
417
	// Alternative implementation:
418
	//  atomically set to false and return the old value
419
	//return exitLoop.exchange(false);
420
}
421
422
template<typename T> void CPUCore<T>::setSlowInstructions()
423
{
424
	slowInstructions = 2;
425
	T::disableLimit();
426
}
427
428
template<typename T> void CPUCore<T>::raiseIRQ()
429
{
430
	assert(IRQStatus >= 0);
431
	if (IRQStatus == 0) {
432
		setSlowInstructions();
433
	}
434
	IRQStatus = IRQStatus + 1;
435
}
436
437
template<typename T> void CPUCore<T>::lowerIRQ()
438
{
439
	IRQStatus = IRQStatus - 1;
440
	assert(IRQStatus >= 0);
441
}
442
443
template<typename T> void CPUCore<T>::raiseNMI()
444
{
445
	assert(NMIStatus >= 0);
446
	if (NMIStatus == 0) {
447
		nmiEdge = true;
448
		setSlowInstructions();
449
	}
450
	NMIStatus++;
451
}
452
453
template<typename T> void CPUCore<T>::lowerNMI()
454
{
455
	NMIStatus--;
456
	assert(NMIStatus >= 0);
457
}
458
459
template<typename T> bool CPUCore<T>::isM1Cycle(unsigned address) const
460
{
461
	// This method should only be called from within a MSXDevice::readMem()
462
	// method. It can be used to check whether the current read action has
463
	// the M1 pin active. The 'address' parameter that is give to readMem()
464
	// should be passed (unchanged) to this method.
465
	//
466
	// This simple implementation works because the rest of the CPUCore
467
	// code is careful to only update the PC register on M1 cycles. In
468
	// practice that means that the PC is (only) updated at the very end of
469
	// every instruction, even if is a multi-byte instruction. Or for
470
	// prefix-instructions the PC is also updated after the prefix is
471
	// fetched (because such instructions activate M1 twice).
472
	return address == getPC();
473
}
474
475
template<typename T> void CPUCore<T>::wait(EmuTime time)
476
{
477
	assert(time >= getCurrentTime());
478
	scheduler.schedule(time);
479
	T::advanceTime(time);
480
}
481
482
template<typename T> EmuTime CPUCore<T>::waitCycles(EmuTime time, unsigned cycles)
483
{
484
	T::add(cycles);
485
	EmuTime time2 = T::calcTime(time, cycles);
486
	// note: time2 is not necessarily equal to T::getTime() because of the
487
	// way how WRITE_PORT() is implemented.
488
	scheduler.schedule(time2);
489
	return time2;
490
}
491
492
template<typename T> void CPUCore<T>::setNextSyncPoint(EmuTime time)
493
{
494
	T::setLimit(time);
495
}
496
497
498
template<typename T> void CPUCore<T>::update(const Setting& setting) noexcept
499
{
500
	if (&setting == &freqLocked) {
501
		doSetFreq();
502
	} else if (&setting == &freqValue) {
503
		doSetFreq();
504
	}
505
}
506
507
template<typename T> void CPUCore<T>::setFreq(unsigned freq_)
508
{
509
	freq = freq_;
510
	doSetFreq();
511
}
512
513
template<typename T> void CPUCore<T>::doSetFreq()
514
{
515
	if (freqLocked.getBoolean()) {
516
		// locked, use value set via setFreq()
517
		T::setFreq(freq);
518
	} else {
519
		// unlocked, use value set by user
520
		T::setFreq(freqValue.getInt());
521
	}
522
}
523
524
525
template<typename T> inline uint8_t CPUCore<T>::READ_PORT(uint16_t port, unsigned cc)
526
{
527
	EmuTime time = T::getTimeFast(cc);
528
	scheduler.schedule(time);
529
	uint8_t result = interface->readIO(port, time);
530
	// note: no forced page-break after IO
531
	return result;
532
}
533
534
template<typename T> inline void CPUCore<T>::WRITE_PORT(uint16_t port, uint8_t value, unsigned cc)
535
{
536
	EmuTime time = T::getTimeFast(cc);
537
	scheduler.schedule(time);
538
	interface->writeIO(port, value, time);
539
	// note: no forced page-break after IO
540
}
541
542
template<typename T> template<bool PRE_PB, bool POST_PB>
543
NEVER_INLINE uint8_t CPUCore<T>::RDMEMslow(unsigned address, unsigned cc)
544
{
545
	interface->tick(CacheLineCounters::NonCachedRead);
546
	// not cached
547
	unsigned high = address >> CacheLine::BITS;
548
        if (readCacheLine[high] == nullptr) {
549
		// try to cache now (not a valid entry, and not yet tried)
550
		auto addrBase = narrow_cast<uint16_t>(address & CacheLine::HIGH);
551
		if (const uint8_t* line = interface->getReadCacheLine(addrBase)) {
552
			// cached ok
553
			T::template PRE_MEM<PRE_PB, POST_PB>(address);
554
			T::template POST_MEM<       POST_PB>(address);
555
			readCacheLine[high] = line - addrBase;
556
			return readCacheLine[high][address];
557
		}
558
	}
559
	// uncacheable
560
	readCacheLine[high] = std::bit_cast<const uint8_t*>(uintptr_t(1));
561
	T::template PRE_MEM<PRE_PB, POST_PB>(address);
562
	EmuTime time = T::getTimeFast(cc);
563
	scheduler.schedule(time);
564
	uint8_t result = interface->readMem(narrow_cast<uint16_t>(address), time);
565
	T::template POST_MEM<POST_PB>(address);
566
	return result;
567
}
568
template<typename T> template<bool PRE_PB, bool POST_PB>
569
ALWAYS_INLINE uint8_t CPUCore<T>::RDMEM_impl2(unsigned address, unsigned cc)
570
{
571
	const uint8_t* line = readCacheLine[address >> CacheLine::BITS];
572
	if (uintptr_t(line) > 1) [[likely]] {
573
		// cached, fast path
574
		T::template PRE_MEM<PRE_PB, POST_PB>(address);
575
		T::template POST_MEM<       POST_PB>(address);
576
		return line[address];
577
	} else {
578
		return RDMEMslow<PRE_PB, POST_PB>(address, cc); // not inlined
579
	}
580
}
581
template<typename T> template<bool PRE_PB, bool POST_PB>
582
ALWAYS_INLINE uint8_t CPUCore<T>::RDMEM_impl(unsigned address, unsigned cc)
583
{
584
	constexpr bool PRE  = T::template Normalize<PRE_PB >::value;
585
	constexpr bool POST = T::template Normalize<POST_PB>::value;
586
	return RDMEM_impl2<PRE, POST>(address, cc);
587
}
588
template<typename T> template<unsigned PC_OFFSET> ALWAYS_INLINE uint8_t CPUCore<T>::RDMEM_OPCODE(unsigned cc)
589
{
590
	// Real Z80 would update the PC register now. In this implementation
591
	// we've chosen to instead update PC only once at the end of the
592
	// instruction. (Of course we made sure this difference is not
593
	// noticeable by the program).
594
	//
595
	// See the comments in isM1Cycle() for the motivation for this
596
	// deviation. Apart from that functional aspect it also turns out to be
597
	// faster to only update PC once per instruction instead of after each
598
	// fetch.
599
	unsigned address = narrow_cast<uint16_t>(getPC() + PC_OFFSET);
600
	return RDMEM_impl<false, false>(address, cc);
601
}
602
template<typename T> ALWAYS_INLINE uint8_t CPUCore<T>::RDMEM(unsigned address, unsigned cc)
603
{
604
	return RDMEM_impl<true, true>(address, cc);
605
}
606
607
template<typename T> template<bool PRE_PB, bool POST_PB>
608
NEVER_INLINE uint16_t CPUCore<T>::RD_WORD_slow(unsigned address, unsigned cc)
609
{
610
	auto res = uint16_t(RDMEM_impl<PRE_PB,  false>(address, cc));
611
	res     |= uint16_t(RDMEM_impl<false, POST_PB>(narrow_cast<uint16_t>(address + 1), cc + T::CC_RDMEM) << 8);
612
	return res;
613
}
614
template<typename T> template<bool PRE_PB, bool POST_PB>
615
ALWAYS_INLINE uint16_t CPUCore<T>::RD_WORD_impl2(unsigned address, unsigned cc)
616
{
617
	const uint8_t* line = readCacheLine[address >> CacheLine::BITS];
618
	if (((address & CacheLine::LOW) != CacheLine::LOW) && (uintptr_t(line) > 1)) [[likely]] {
619
		// fast path: cached and two bytes in same cache line
620
		T::template PRE_WORD<PRE_PB, POST_PB>(address);
621
		T::template POST_WORD<       POST_PB>(address);
622
		return Endian::read_UA_L16(&line[address]);
623
	} else {
624
		// slow path, not inline
625
		return RD_WORD_slow<PRE_PB, POST_PB>(address, cc);
626
	}
627
}
628
template<typename T> template<bool PRE_PB, bool POST_PB>
629
ALWAYS_INLINE uint16_t CPUCore<T>::RD_WORD_impl(unsigned address, unsigned cc)
630
{
631
	constexpr bool PRE  = T::template Normalize<PRE_PB >::value;
632
	constexpr bool POST = T::template Normalize<POST_PB>::value;
633
	return RD_WORD_impl2<PRE, POST>(address, cc);
634
}
635
template<typename T> template<unsigned PC_OFFSET> ALWAYS_INLINE uint16_t CPUCore<T>::RD_WORD_PC(unsigned cc)
636
{
637
	unsigned addr = narrow_cast<uint16_t>(getPC() + PC_OFFSET);
638
	return RD_WORD_impl<false, false>(addr, cc);
639
}
640
template<typename T> ALWAYS_INLINE uint16_t CPUCore<T>::RD_WORD(
641
	unsigned address, unsigned cc)
642
{
643
	return RD_WORD_impl<true, true>(address, cc);
644
}
645
646
template<typename T> template<bool PRE_PB, bool POST_PB>
647
NEVER_INLINE void CPUCore<T>::WRMEMslow(unsigned address, uint8_t value, unsigned cc)
648
{
649
	interface->tick(CacheLineCounters::NonCachedWrite);
650
	// not cached
651
	unsigned high = address >> CacheLine::BITS;
652
	if (writeCacheLine[high] == nullptr) {
653
		// try to cache now
654
		auto addrBase = narrow_cast<uint16_t>(address & CacheLine::HIGH);
655
		if (uint8_t* line = interface->getWriteCacheLine(addrBase)) {
656
			// cached ok
657
			T::template PRE_MEM<PRE_PB, POST_PB>(address);
658
			T::template POST_MEM<       POST_PB>(address);
659
			writeCacheLine[high] = line - addrBase;
660
			writeCacheLine[high][address] = value;
661
			return;
662
		}
663
	}
664
	// uncacheable
665
	writeCacheLine[high] = std::bit_cast<uint8_t*>(uintptr_t(1));
666
	T::template PRE_MEM<PRE_PB, POST_PB>(address);
667
	EmuTime time = T::getTimeFast(cc);
668
	scheduler.schedule(time);
669
	interface->writeMem(narrow_cast<uint16_t>(address), value, time);
670
	T::template POST_MEM<POST_PB>(address);
671
}
672
template<typename T> template<bool PRE_PB, bool POST_PB>
673
ALWAYS_INLINE void CPUCore<T>::WRMEM_impl2(
674
	unsigned address, uint8_t value, unsigned cc)
675
{
676
	uint8_t* line = writeCacheLine[address >> CacheLine::BITS];
677
	if (uintptr_t(line) > 1) [[likely]] {
678
		// cached, fast path
679
		T::template PRE_MEM<PRE_PB, POST_PB>(address);
680
		T::template POST_MEM<       POST_PB>(address);
681
		line[address] = value;
682
	} else {
683
		WRMEMslow<PRE_PB, POST_PB>(address, value, cc); // not inlined
684
	}
685
}
686
template<typename T> template<bool PRE_PB, bool POST_PB>
687
ALWAYS_INLINE void CPUCore<T>::WRMEM_impl(
688
	unsigned address, uint8_t value, unsigned cc)
689
{
690
	constexpr bool PRE  = T::template Normalize<PRE_PB >::value;
691
	constexpr bool POST = T::template Normalize<POST_PB>::value;
692
	WRMEM_impl2<PRE, POST>(address, value, cc);
693
}
694
template<typename T> ALWAYS_INLINE void CPUCore<T>::WRMEM(
695
	unsigned address, uint8_t value, unsigned cc)
696
{
697
	WRMEM_impl<true, true>(address, value, cc);
698
}
699
700
template<typename T> NEVER_INLINE void CPUCore<T>::WR_WORD_slow(
701
	unsigned address, uint16_t value, unsigned cc)
702
{
703
	WRMEM_impl<true, false>(                      address,      uint8_t(value & 255), cc);
704
	WRMEM_impl<false, true>(narrow_cast<uint16_t>(address + 1), uint8_t(value >> 8),  cc + T::CC_WRMEM);
705
}
706
template<typename T> ALWAYS_INLINE void CPUCore<T>::WR_WORD(
707
	unsigned address, uint16_t value, unsigned cc)
708
{
709
	uint8_t* line = writeCacheLine[address >> CacheLine::BITS];
710
	if (((address & CacheLine::LOW) != CacheLine::LOW) && (uintptr_t(line) > 1)) [[likely]] {
711
		// fast path: cached and two bytes in same cache line
712
		T::template PRE_WORD<true, true>(address);
713
		T::template POST_WORD<     true>(address);
714
		Endian::write_UA_L16(&line[address], value);
715
	} else {
716
		// slow path, not inline
717
		WR_WORD_slow(address, value, cc);
718
	}
719
}
720
721
// same as WR_WORD, but writes high byte first
722
template<typename T> template<bool PRE_PB, bool POST_PB>
723
NEVER_INLINE void CPUCore<T>::WR_WORD_rev_slow(
724
	unsigned address, uint16_t value, unsigned cc)
725
{
726
	WRMEM_impl<PRE_PB,  false>(narrow_cast<uint16_t>(address + 1), uint8_t(value >> 8),  cc);
727
	WRMEM_impl<false, POST_PB>(                      address,      uint8_t(value & 255), cc + T::CC_WRMEM);
728
}
729
template<typename T> template<bool PRE_PB, bool POST_PB>
730
ALWAYS_INLINE void CPUCore<T>::WR_WORD_rev2(
731
	unsigned address, uint16_t value, unsigned cc)
732
{
733
	uint8_t* line = writeCacheLine[address >> CacheLine::BITS];
734
	if (((address & CacheLine::LOW) != CacheLine::LOW) && (uintptr_t(line) > 1)) [[likely]] {
735
		// fast path: cached and two bytes in same cache line
736
		T::template PRE_WORD<PRE_PB, POST_PB>(address);
737
		T::template POST_WORD<       POST_PB>(address);
738
		Endian::write_UA_L16(&line[address], value);
739
	} else {
740
		// slow path, not inline
741
		WR_WORD_rev_slow<PRE_PB, POST_PB>(address, value, cc);
742
	}
743
}
744
template<typename T> template<bool PRE_PB, bool POST_PB>
745
ALWAYS_INLINE void CPUCore<T>::WR_WORD_rev(
746
	unsigned address, uint16_t value, unsigned cc)
747
{
748
	constexpr bool PRE  = T::template Normalize<PRE_PB >::value;
749
	constexpr bool POST = T::template Normalize<POST_PB>::value;
750
	WR_WORD_rev2<PRE, POST>(address, value, cc);
751
}
752
753
754
// NMI interrupt
755
template<typename T> inline void CPUCore<T>::nmi()
756
{
757
	incR(1);
758
	setHALT(false);
759
	setIFF1(false);
760
	PUSH<T::EE_NMI_1>(getPC());
761
	setPC(0x0066);
762
	T::add(T::CC_NMI);
763
}
764
765
// IM0 interrupt
766
template<typename T> inline void CPUCore<T>::irq0()
767
{
768
	// TODO current implementation only works for 1-byte instructions
769
	//      ok for MSX
770
	assert(interface->readIRQVector() == 0xFF);
771
	incR(1);
772
	setHALT(false);
773
	setIFF1(false);
774
	setIFF2(false);
775
	PUSH<T::EE_IRQ0_1>(getPC());
776
	setPC(0x0038);
777
	T::setMemPtr(getPC());
778
	T::add(T::CC_IRQ0);
779
}
780
781
// IM1 interrupt
782
template<typename T> inline void CPUCore<T>::irq1()
783
{
784
	incR(1);
785
	setHALT(false);
786
	setIFF1(false);
787
	setIFF2(false);
788
	PUSH<T::EE_IRQ1_1>(getPC());
789
	setPC(0x0038);
790
	T::setMemPtr(getPC());
791
	T::add(T::CC_IRQ1);
792
}
793
794
// IM2 interrupt
795
template<typename T> inline void CPUCore<T>::irq2()
796
{
797
	incR(1);
798
	setHALT(false);
799
	setIFF1(false);
800
	setIFF2(false);
801
	PUSH<T::EE_IRQ2_1>(getPC());
802
	unsigned x = interface->readIRQVector() | (getI() << 8);
803
	setPC(RD_WORD(x, T::CC_IRQ2_2));
804
	T::setMemPtr(getPC());
805
	T::add(T::CC_IRQ2);
806
}
807
808
template<typename T>
809
void CPUCore<T>::executeInstructions()
810
{
811
	checkNoCurrentFlags();
812
#ifdef USE_COMPUTED_GOTO
813
	// Addresses of all main-opcode routines,
814
	// Note that 40/49/53/5B/64/6D/7F is replaced by 00 (ld r,r == nop)
815
	static std::array<void*, 256> opcodeTable = {
816
		&&op00, &&op01, &&op02, &&op03, &&op04, &&op05, &&op06, &&op07,
817
		&&op08, &&op09, &&op0A, &&op0B, &&op0C, &&op0D, &&op0E, &&op0F,
818
		&&op10, &&op11, &&op12, &&op13, &&op14, &&op15, &&op16, &&op17,
819
		&&op18, &&op19, &&op1A, &&op1B, &&op1C, &&op1D, &&op1E, &&op1F,
820
		&&op20, &&op21, &&op22, &&op23, &&op24, &&op25, &&op26, &&op27,
821
		&&op28, &&op29, &&op2A, &&op2B, &&op2C, &&op2D, &&op2E, &&op2F,
822
		&&op30, &&op31, &&op32, &&op33, &&op34, &&op35, &&op36, &&op37,
823
		&&op38, &&op39, &&op3A, &&op3B, &&op3C, &&op3D, &&op3E, &&op3F,
824
		&&op00, &&op41, &&op42, &&op43, &&op44, &&op45, &&op46, &&op47,
825
		&&op48, &&op00, &&op4A, &&op4B, &&op4C, &&op4D, &&op4E, &&op4F,
826
		&&op50, &&op51, &&op00, &&op53, &&op54, &&op55, &&op56, &&op57,
827
		&&op58, &&op59, &&op5A, &&op00, &&op5C, &&op5D, &&op5E, &&op5F,
828
		&&op60, &&op61, &&op62, &&op63, &&op00, &&op65, &&op66, &&op67,
829
		&&op68, &&op69, &&op6A, &&op6B, &&op6C, &&op00, &&op6E, &&op6F,
830
		&&op70, &&op71, &&op72, &&op73, &&op74, &&op75, &&op76, &&op77,
831
		&&op78, &&op79, &&op7A, &&op7B, &&op7C, &&op7D, &&op7E, &&op00,
832
		&&op80, &&op81, &&op82, &&op83, &&op84, &&op85, &&op86, &&op87,
833
		&&op88, &&op89, &&op8A, &&op8B, &&op8C, &&op8D, &&op8E, &&op8F,
834
		&&op90, &&op91, &&op92, &&op93, &&op94, &&op95, &&op96, &&op97,
835
		&&op98, &&op99, &&op9A, &&op9B, &&op9C, &&op9D, &&op9E, &&op9F,
836
		&&opA0, &&opA1, &&opA2, &&opA3, &&opA4, &&opA5, &&opA6, &&opA7,
837
		&&opA8, &&opA9, &&opAA, &&opAB, &&opAC, &&opAD, &&opAE, &&opAF,
838
		&&opB0, &&opB1, &&opB2, &&opB3, &&opB4, &&opB5, &&opB6, &&opB7,
839
		&&opB8, &&opB9, &&opBA, &&opBB, &&opBC, &&opBD, &&opBE, &&opBF,
840
		&&opC0, &&opC1, &&opC2, &&opC3, &&opC4, &&opC5, &&opC6, &&opC7,
841
		&&opC8, &&opC9, &&opCA, &&opCB, &&opCC, &&opCD, &&opCE, &&opCF,
842
		&&opD0, &&opD1, &&opD2, &&opD3, &&opD4, &&opD5, &&opD6, &&opD7,
843
		&&opD8, &&opD9, &&opDA, &&opDB, &&opDC, &&opDD, &&opDE, &&opDF,
844
		&&opE0, &&opE1, &&opE2, &&opE3, &&opE4, &&opE5, &&opE6, &&opE7,
845
		&&opE8, &&opE9, &&opEA, &&opEB, &&opEC, &&opED, &&opEE, &&opEF,
846
		&&opF0, &&opF1, &&opF2, &&opF3, &&opF4, &&opF5, &&opF6, &&opF7,
847
		&&opF8, &&opF9, &&opFA, &&opFB, &&opFC, &&opFD, &&opFE, &&opFF,
848
	};
849
850
// Check T::limitReached(). If it's OK to continue,
851
// fetch and execute next instruction.
852
#define NEXT \
853
	setPC(getPC() + ii.length); \
854
	T::add(ii.cycles); \
855
	T::R800Refresh(*this); \
856
	if (!T::limitReached()) [[likely]] { \
857
		incR(1); \
858
		unsigned address = getPC(); \
859
		const uint8_t* line = readCacheLine[address >> CacheLine::BITS]; \
860
		if (uintptr_t(line) > 1) [[likely]] { \
861
			T::template PRE_MEM<false, false>(address); \
862
			T::template POST_MEM<      false>(address); \
863
			uint8_t op = line[address]; \
864
			goto *(opcodeTable[op]); \
865
		} else { \
866
			goto fetchSlow; \
867
		} \
868
	} \
869
	return;
870
871
// After some instructions we must always exit the CPU loop (ei, halt, retn)
872
#define NEXT_STOP \
873
	setPC(getPC() + ii.length); \
874
	T::add(ii.cycles); \
875
	T::R800Refresh(*this); \
876
	assert(T::limitReached()); \
877
	return;
878
879
#define NEXT_EI \
880
	setPC(getPC() + ii.length); \
881
	T::add(ii.cycles); \
882
	/* !! NO T::R800Refresh(*this); !! */ \
883
	assert(T::limitReached()); \
884
	return;
885
886
// Define a label (instead of case in a switch statement)
887
#define CASE(X) op##X:
888
889
#else // USE_COMPUTED_GOTO
890
891
#define NEXT \
892
	setPC(getPC() + ii.length); \
893
	T::add(ii.cycles); \
894
	T::R800Refresh(*this); \
895
	if (!T::limitReached()) [[likely]] { \
896
		goto start; \
897
	} \
898
	return;
899
900
#define NEXT_STOP \
901
	setPC(getPC() + ii.length); \
902
	T::add(ii.cycles); \
903
	T::R800Refresh(*this); \
904
	assert(T::limitReached()); \
905
	return;
906
907
#define NEXT_EI \
908
	setPC(getPC() + ii.length); \
909
	T::add(ii.cycles); \
910
	/* !! NO T::R800Refresh(*this); !! */ \
911
	assert(T::limitReached()); \
912
	return;
913
914
#define CASE(X) case 0x##X:
915
916
#endif // USE_COMPUTED_GOTO
917
918
#ifndef USE_COMPUTED_GOTO
919
start:
920
#endif
921
	unsigned ixy; // for dd_cb/fd_cb
922
	uint8_t opcodeMain = RDMEM_OPCODE<0>(T::CC_MAIN);
923
	incR(1);
924
#ifdef USE_COMPUTED_GOTO
925
	goto *(opcodeTable[opcodeMain]);
926
927
fetchSlow: {
928
	unsigned address = getPC();
929
	uint8_t opcodeSlow = RDMEMslow<false, false>(address, T::CC_MAIN);
930
	goto *(opcodeTable[opcodeSlow]);
931
}
932
#endif
933
934
#ifndef USE_COMPUTED_GOTO
935
MAYBE_UNUSED_LABEL switchOpcode:
936
	switch (opcodeMain) {
937
CASE(40) // ld b,b
938
CASE(49) // ld c,c
939
CASE(52) // ld d,d
940
CASE(5B) // ld e,e
941
CASE(64) // ld h,h
942
CASE(6D) // ld l,l
943
CASE(7F) // ld a,a
944
#endif
945
CASE(00) { II ii = nop(); NEXT; }
946
CASE(07) { II ii = rlca(); NEXT; }
947
CASE(0F) { II ii = rrca(); NEXT; }
948
CASE(17) { II ii = rla();  NEXT; }
949
CASE(1F) { II ii = rra();  NEXT; }
950
CASE(08) { II ii = ex_af_af(); NEXT; }
951
CASE(27) { II ii = daa(); NEXT; }
952
CASE(2F) { II ii = cpl(); NEXT; }
953
CASE(37) { II ii = scf(); NEXT; }
954
CASE(3F) { II ii = ccf(); NEXT; }
955
CASE(20) { II ii = jr(CondNZ()); NEXT; }
956
CASE(28) { II ii = jr(CondZ ()); NEXT; }
957
CASE(30) { II ii = jr(CondNC()); NEXT; }
958
CASE(38) { II ii = jr(CondC ()); NEXT; }
959
CASE(18) { II ii = jr(CondTrue()); NEXT; }
960
CASE(10) { II ii = djnz(); NEXT; }
961
CASE(32) { II ii = ld_xbyte_a(); NEXT; }
962
CASE(3A) { II ii = ld_a_xbyte(); NEXT; }
963
CASE(22) { II ii = ld_xword_SS<HL,0>(); NEXT; }
964
CASE(2A) { II ii = ld_SS_xword<HL,0>(); NEXT; }
965
CASE(02) { II ii = ld_SS_a<BC>(); NEXT; }
966
CASE(12) { II ii = ld_SS_a<DE>(); NEXT; }
967
CASE(1A) { II ii = ld_a_SS<DE>(); NEXT; }
968
CASE(0A) { II ii = ld_a_SS<BC>(); NEXT; }
969
CASE(03) { II ii = inc_SS<BC,0>(); NEXT; }
970
CASE(13) { II ii = inc_SS<DE,0>(); NEXT; }
971
CASE(23) { II ii = inc_SS<HL,0>(); NEXT; }
972
CASE(33) { II ii = inc_SS<SP,0>(); NEXT; }
973
CASE(0B) { II ii = dec_SS<BC,0>(); NEXT; }
974
CASE(1B) { II ii = dec_SS<DE,0>(); NEXT; }
975
CASE(2B) { II ii = dec_SS<HL,0>(); NEXT; }
976
CASE(3B) { II ii = dec_SS<SP,0>(); NEXT; }
977
CASE(09) { II ii = add_SS_TT<HL,BC,0>(); NEXT; }
978
CASE(19) { II ii = add_SS_TT<HL,DE,0>(); NEXT; }
979
CASE(29) { II ii = add_SS_SS<HL   ,0>(); NEXT; }
980
CASE(39) { II ii = add_SS_TT<HL,SP,0>(); NEXT; }
981
CASE(01) { II ii = ld_SS_word<BC,0>(); NEXT; }
982
CASE(11) { II ii = ld_SS_word<DE,0>(); NEXT; }
983
CASE(21) { II ii = ld_SS_word<HL,0>(); NEXT; }
984
CASE(31) { II ii = ld_SS_word<SP,0>(); NEXT; }
985
CASE(04) { II ii = inc_R<B,0>(); NEXT; }
986
CASE(0C) { II ii = inc_R<C,0>(); NEXT; }
987
CASE(14) { II ii = inc_R<D,0>(); NEXT; }
988
CASE(1C) { II ii = inc_R<E,0>(); NEXT; }
989
CASE(24) { II ii = inc_R<H,0>(); NEXT; }
990
CASE(2C) { II ii = inc_R<L,0>(); NEXT; }
991
CASE(3C) { II ii = inc_R<A,0>(); NEXT; }
992
CASE(34) { II ii = inc_xhl();  NEXT; }
993
CASE(05) { II ii = dec_R<B,0>(); NEXT; }
994
CASE(0D) { II ii = dec_R<C,0>(); NEXT; }
995
CASE(15) { II ii = dec_R<D,0>(); NEXT; }
996
CASE(1D) { II ii = dec_R<E,0>(); NEXT; }
997
CASE(25) { II ii = dec_R<H,0>(); NEXT; }
998
CASE(2D) { II ii = dec_R<L,0>(); NEXT; }
999
CASE(3D) { II ii = dec_R<A,0>(); NEXT; }
1000
CASE(35) { II ii = dec_xhl();  NEXT; }
1001
CASE(06) { II ii = ld_R_byte<B,0>(); NEXT; }
1002
CASE(0E) { II ii = ld_R_byte<C,0>(); NEXT; }
1003
CASE(16) { II ii = ld_R_byte<D,0>(); NEXT; }
1004
CASE(1E) { II ii = ld_R_byte<E,0>(); NEXT; }
1005
CASE(26) { II ii = ld_R_byte<H,0>(); NEXT; }
1006
CASE(2E) { II ii = ld_R_byte<L,0>(); NEXT; }
1007
CASE(3E) { II ii = ld_R_byte<A,0>(); NEXT; }
1008
CASE(36) { II ii = ld_xhl_byte();  NEXT; }
1009
1010
CASE(41) { II ii = ld_R_R<B,C,0>(); NEXT; }
1011
CASE(42) { II ii = ld_R_R<B,D,0>(); NEXT; }
1012
CASE(43) { II ii = ld_R_R<B,E,0>(); NEXT; }
1013
CASE(44) { II ii = ld_R_R<B,H,0>(); NEXT; }
1014
CASE(45) { II ii = ld_R_R<B,L,0>(); NEXT; }
1015
CASE(47) { II ii = ld_R_R<B,A,0>(); NEXT; }
1016
CASE(48) { II ii = ld_R_R<C,B,0>(); NEXT; }
1017
CASE(4A) { II ii = ld_R_R<C,D,0>(); NEXT; }
1018
CASE(4B) { II ii = ld_R_R<C,E,0>(); NEXT; }
1019
CASE(4C) { II ii = ld_R_R<C,H,0>(); NEXT; }
1020
CASE(4D) { II ii = ld_R_R<C,L,0>(); NEXT; }
1021
CASE(4F) { II ii = ld_R_R<C,A,0>(); NEXT; }
1022
CASE(50) { II ii = ld_R_R<D,B,0>(); NEXT; }
1023
CASE(51) { II ii = ld_R_R<D,C,0>(); NEXT; }
1024
CASE(53) { II ii = ld_R_R<D,E,0>(); NEXT; }
1025
CASE(54) { II ii = ld_R_R<D,H,0>(); NEXT; }
1026
CASE(55) { II ii = ld_R_R<D,L,0>(); NEXT; }
1027
CASE(57) { II ii = ld_R_R<D,A,0>(); NEXT; }
1028
CASE(58) { II ii = ld_R_R<E,B,0>(); NEXT; }
1029
CASE(59) { II ii = ld_R_R<E,C,0>(); NEXT; }
1030
CASE(5A) { II ii = ld_R_R<E,D,0>(); NEXT; }
1031
CASE(5C) { II ii = ld_R_R<E,H,0>(); NEXT; }
1032
CASE(5D) { II ii = ld_R_R<E,L,0>(); NEXT; }
1033
CASE(5F) { II ii = ld_R_R<E,A,0>(); NEXT; }
1034
CASE(60) { II ii = ld_R_R<H,B,0>(); NEXT; }
1035
CASE(61) { II ii = ld_R_R<H,C,0>(); NEXT; }
1036
CASE(62) { II ii = ld_R_R<H,D,0>(); NEXT; }
1037
CASE(63) { II ii = ld_R_R<H,E,0>(); NEXT; }
1038
CASE(65) { II ii = ld_R_R<H,L,0>(); NEXT; }
1039
CASE(67) { II ii = ld_R_R<H,A,0>(); NEXT; }
1040
CASE(68) { II ii = ld_R_R<L,B,0>(); NEXT; }
1041
CASE(69) { II ii = ld_R_R<L,C,0>(); NEXT; }
1042
CASE(6A) { II ii = ld_R_R<L,D,0>(); NEXT; }
1043
CASE(6B) { II ii = ld_R_R<L,E,0>(); NEXT; }
1044
CASE(6C) { II ii = ld_R_R<L,H,0>(); NEXT; }
1045
CASE(6F) { II ii = ld_R_R<L,A,0>(); NEXT; }
1046
CASE(78) { II ii = ld_R_R<A,B,0>(); NEXT; }
1047
CASE(79) { II ii = ld_R_R<A,C,0>(); NEXT; }
1048
CASE(7A) { II ii = ld_R_R<A,D,0>(); NEXT; }
1049
CASE(7B) { II ii = ld_R_R<A,E,0>(); NEXT; }
1050
CASE(7C) { II ii = ld_R_R<A,H,0>(); NEXT; }
1051
CASE(7D) { II ii = ld_R_R<A,L,0>(); NEXT; }
1052
CASE(70) { II ii = ld_xhl_R<B>(); NEXT; }
1053
CASE(71) { II ii = ld_xhl_R<C>(); NEXT; }
1054
CASE(72) { II ii = ld_xhl_R<D>(); NEXT; }
1055
CASE(73) { II ii = ld_xhl_R<E>(); NEXT; }
1056
CASE(74) { II ii = ld_xhl_R<H>(); NEXT; }
1057
CASE(75) { II ii = ld_xhl_R<L>(); NEXT; }
1058
CASE(77) { II ii = ld_xhl_R<A>(); NEXT; }
1059
CASE(46) { II ii = ld_R_xhl<B>(); NEXT; }
1060
CASE(4E) { II ii = ld_R_xhl<C>(); NEXT; }
1061
CASE(56) { II ii = ld_R_xhl<D>(); NEXT; }
1062
CASE(5E) { II ii = ld_R_xhl<E>(); NEXT; }
1063
CASE(66) { II ii = ld_R_xhl<H>(); NEXT; }
1064
CASE(6E) { II ii = ld_R_xhl<L>(); NEXT; }
1065
CASE(7E) { II ii = ld_R_xhl<A>(); NEXT; }
1066
CASE(76) { II ii = halt(); NEXT_STOP; }
1067
1068
CASE(80) { II ii = add_a_R<B,0>(); NEXT; }
1069
CASE(81) { II ii = add_a_R<C,0>(); NEXT; }
1070
CASE(82) { II ii = add_a_R<D,0>(); NEXT; }
1071
CASE(83) { II ii = add_a_R<E,0>(); NEXT; }
1072
CASE(84) { II ii = add_a_R<H,0>(); NEXT; }
1073
CASE(85) { II ii = add_a_R<L,0>(); NEXT; }
1074
CASE(86) { II ii = add_a_xhl();   NEXT; }
1075
CASE(87) { II ii = add_a_a();     NEXT; }
1076
CASE(88) { II ii = adc_a_R<B,0>(); NEXT; }
1077
CASE(89) { II ii = adc_a_R<C,0>(); NEXT; }
1078
CASE(8A) { II ii = adc_a_R<D,0>(); NEXT; }
1079
CASE(8B) { II ii = adc_a_R<E,0>(); NEXT; }
1080
CASE(8C) { II ii = adc_a_R<H,0>(); NEXT; }
1081
CASE(8D) { II ii = adc_a_R<L,0>(); NEXT; }
1082
CASE(8E) { II ii = adc_a_xhl();   NEXT; }
1083
CASE(8F) { II ii = adc_a_a();     NEXT; }
1084
CASE(90) { II ii = sub_R<B,0>(); NEXT; }
1085
CASE(91) { II ii = sub_R<C,0>(); NEXT; }
1086
CASE(92) { II ii = sub_R<D,0>(); NEXT; }
1087
CASE(93) { II ii = sub_R<E,0>(); NEXT; }
1088
CASE(94) { II ii = sub_R<H,0>(); NEXT; }
1089
CASE(95) { II ii = sub_R<L,0>(); NEXT; }
1090
CASE(96) { II ii = sub_xhl();   NEXT; }
1091
CASE(97) { II ii = sub_a();     NEXT; }
1092
CASE(98) { II ii = sbc_a_R<B,0>(); NEXT; }
1093
CASE(99) { II ii = sbc_a_R<C,0>(); NEXT; }
1094
CASE(9A) { II ii = sbc_a_R<D,0>(); NEXT; }
1095
CASE(9B) { II ii = sbc_a_R<E,0>(); NEXT; }
1096
CASE(9C) { II ii = sbc_a_R<H,0>(); NEXT; }
1097
CASE(9D) { II ii = sbc_a_R<L,0>(); NEXT; }
1098
CASE(9E) { II ii = sbc_a_xhl();   NEXT; }
1099
CASE(9F) { II ii = sbc_a_a();     NEXT; }
1100
CASE(A0) { II ii = and_R<B,0>(); NEXT; }
1101
CASE(A1) { II ii = and_R<C,0>(); NEXT; }
1102
CASE(A2) { II ii = and_R<D,0>(); NEXT; }
1103
CASE(A3) { II ii = and_R<E,0>(); NEXT; }
1104
CASE(A4) { II ii = and_R<H,0>(); NEXT; }
1105
CASE(A5) { II ii = and_R<L,0>(); NEXT; }
1106
CASE(A6) { II ii = and_xhl();   NEXT; }
1107
CASE(A7) { II ii = and_a();     NEXT; }
1108
CASE(A8) { II ii = xor_R<B,0>(); NEXT; }
1109
CASE(A9) { II ii = xor_R<C,0>(); NEXT; }
1110
CASE(AA) { II ii = xor_R<D,0>(); NEXT; }
1111
CASE(AB) { II ii = xor_R<E,0>(); NEXT; }
1112
CASE(AC) { II ii = xor_R<H,0>(); NEXT; }
1113
CASE(AD) { II ii = xor_R<L,0>(); NEXT; }
1114
CASE(AE) { II ii = xor_xhl();   NEXT; }
1115
CASE(AF) { II ii = xor_a();     NEXT; }
1116
CASE(B0) { II ii = or_R<B,0>(); NEXT; }
1117
CASE(B1) { II ii = or_R<C,0>(); NEXT; }
1118
CASE(B2) { II ii = or_R<D,0>(); NEXT; }
1119
CASE(B3) { II ii = or_R<E,0>(); NEXT; }
1120
CASE(B4) { II ii = or_R<H,0>(); NEXT; }
1121
CASE(B5) { II ii = or_R<L,0>(); NEXT; }
1122
CASE(B6) { II ii = or_xhl();   NEXT; }
1123
CASE(B7) { II ii = or_a();     NEXT; }
1124
CASE(B8) { II ii = cp_R<B,0>(); NEXT; }
1125
CASE(B9) { II ii = cp_R<C,0>(); NEXT; }
1126
CASE(BA) { II ii = cp_R<D,0>(); NEXT; }
1127
CASE(BB) { II ii = cp_R<E,0>(); NEXT; }
1128
CASE(BC) { II ii = cp_R<H,0>(); NEXT; }
1129
CASE(BD) { II ii = cp_R<L,0>(); NEXT; }
1130
CASE(BE) { II ii = cp_xhl();   NEXT; }
1131
CASE(BF) { II ii = cp_a();     NEXT; }
1132
1133
CASE(D3) { II ii = out_byte_a(); NEXT; }
1134
CASE(DB) { II ii = in_a_byte();  NEXT; }
1135
CASE(D9) { II ii = exx(); NEXT; }
1136
CASE(E3) { II ii = ex_xsp_SS<HL,0>(); NEXT; }
1137
CASE(EB) { II ii = ex_de_hl(); NEXT; }
1138
CASE(E9) { II ii = jp_SS<HL,0>(); NEXT; }
1139
CASE(F9) { II ii = ld_sp_SS<HL,0>(); NEXT; }
1140
CASE(F3) { II ii = di(); NEXT; }
1141
CASE(FB) { II ii = ei(); NEXT_EI; }
1142
CASE(C6) { II ii = add_a_byte(); NEXT; }
1143
CASE(CE) { II ii = adc_a_byte(); NEXT; }
1144
CASE(D6) { II ii = sub_byte();   NEXT; }
1145
CASE(DE) { II ii = sbc_a_byte(); NEXT; }
1146
CASE(E6) { II ii = and_byte();   NEXT; }
1147
CASE(EE) { II ii = xor_byte();   NEXT; }
1148
CASE(F6) { II ii = or_byte();    NEXT; }
1149
CASE(FE) { II ii = cp_byte();    NEXT; }
1150
CASE(C0) { II ii = ret(CondNZ()); NEXT; }
1151
CASE(C8) { II ii = ret(CondZ ()); NEXT; }
1152
CASE(D0) { II ii = ret(CondNC()); NEXT; }
1153
CASE(D8) { II ii = ret(CondC ()); NEXT; }
1154
CASE(E0) { II ii = ret(CondPO()); NEXT; }
1155
CASE(E8) { II ii = ret(CondPE()); NEXT; }
1156
CASE(F0) { II ii = ret(CondP ()); NEXT; }
1157
CASE(F8) { II ii = ret(CondM ()); NEXT; }
1158
CASE(C9) { II ii = ret();         NEXT; }
1159
CASE(C2) { II ii = jp(CondNZ()); NEXT; }
1160
CASE(CA) { II ii = jp(CondZ ()); NEXT; }
1161
CASE(D2) { II ii = jp(CondNC()); NEXT; }
1162
CASE(DA) { II ii = jp(CondC ()); NEXT; }
1163
CASE(E2) { II ii = jp(CondPO()); NEXT; }
1164
CASE(EA) { II ii = jp(CondPE()); NEXT; }
1165
CASE(F2) { II ii = jp(CondP ()); NEXT; }
1166
CASE(FA) { II ii = jp(CondM ()); NEXT; }
1167
CASE(C3) { II ii = jp(CondTrue()); NEXT; }
1168
CASE(C4) { II ii = call(CondNZ()); NEXT; }
1169
CASE(CC) { II ii = call(CondZ ()); NEXT; }
1170
CASE(D4) { II ii = call(CondNC()); NEXT; }
1171
CASE(DC) { II ii = call(CondC ()); NEXT; }
1172
CASE(E4) { II ii = call(CondPO()); NEXT; }
1173
CASE(EC) { II ii = call(CondPE()); NEXT; }
1174
CASE(F4) { II ii = call(CondP ()); NEXT; }
1175
CASE(FC) { II ii = call(CondM ()); NEXT; }
1176
CASE(CD) { II ii = call(CondTrue()); NEXT; }
1177
CASE(C1) { II ii = pop_SS <BC,0>(); NEXT; }
1178
CASE(D1) { II ii = pop_SS <DE,0>(); NEXT; }
1179
CASE(E1) { II ii = pop_SS <HL,0>(); NEXT; }
1180
CASE(F1) { II ii = pop_SS <AF,0>(); NEXT; }
1181
CASE(C5) { II ii = push_SS<BC,0>(); NEXT; }
1182
CASE(D5) { II ii = push_SS<DE,0>(); NEXT; }
1183
CASE(E5) { II ii = push_SS<HL,0>(); NEXT; }
1184
CASE(F5) { II ii = push_SS<AF,0>(); NEXT; }
1185
CASE(C7) { II ii = rst<0x00>(); NEXT; }
1186
CASE(CF) { II ii = rst<0x08>(); NEXT; }
1187
CASE(D7) { II ii = rst<0x10>(); NEXT; }
1188
CASE(DF) { II ii = rst<0x18>(); NEXT; }
1189
CASE(E7) { II ii = rst<0x20>(); NEXT; }
1190
CASE(EF) { II ii = rst<0x28>(); NEXT; }
1191
CASE(F7) { II ii = rst<0x30>(); NEXT; }
1192
CASE(FF) { II ii = rst<0x38>(); NEXT; }
1193
CASE(CB) {
1194
	setPC(getPC() + 1); // M1 cycle at this point
1195
	uint8_t cb_opcode = RDMEM_OPCODE<0>(T::CC_PREFIX);
1196
	incR(1);
1197
	switch (cb_opcode) {
1198
		case 0x00: { II ii = rlc_R<B>(); NEXT; }
1199
		case 0x01: { II ii = rlc_R<C>(); NEXT; }
1200
		case 0x02: { II ii = rlc_R<D>(); NEXT; }
1201
		case 0x03: { II ii = rlc_R<E>(); NEXT; }
1202
		case 0x04: { II ii = rlc_R<H>(); NEXT; }
1203
		case 0x05: { II ii = rlc_R<L>(); NEXT; }
1204
		case 0x07: { II ii = rlc_R<A>(); NEXT; }
1205
		case 0x06: { II ii = rlc_xhl();  NEXT; }
1206
		case 0x08: { II ii = rrc_R<B>(); NEXT; }
1207
		case 0x09: { II ii = rrc_R<C>(); NEXT; }
1208
		case 0x0a: { II ii = rrc_R<D>(); NEXT; }
1209
		case 0x0b: { II ii = rrc_R<E>(); NEXT; }
1210
		case 0x0c: { II ii = rrc_R<H>(); NEXT; }
1211
		case 0x0d: { II ii = rrc_R<L>(); NEXT; }
1212
		case 0x0f: { II ii = rrc_R<A>(); NEXT; }
1213
		case 0x0e: { II ii = rrc_xhl();  NEXT; }
1214
		case 0x10: { II ii = rl_R<B>(); NEXT; }
1215
		case 0x11: { II ii = rl_R<C>(); NEXT; }
1216
		case 0x12: { II ii = rl_R<D>(); NEXT; }
1217
		case 0x13: { II ii = rl_R<E>(); NEXT; }
1218
		case 0x14: { II ii = rl_R<H>(); NEXT; }
1219
		case 0x15: { II ii = rl_R<L>(); NEXT; }
1220
		case 0x17: { II ii = rl_R<A>(); NEXT; }
1221
		case 0x16: { II ii = rl_xhl();  NEXT; }
1222
		case 0x18: { II ii = rr_R<B>(); NEXT; }
1223
		case 0x19: { II ii = rr_R<C>(); NEXT; }
1224
		case 0x1a: { II ii = rr_R<D>(); NEXT; }
1225
		case 0x1b: { II ii = rr_R<E>(); NEXT; }
1226
		case 0x1c: { II ii = rr_R<H>(); NEXT; }
1227
		case 0x1d: { II ii = rr_R<L>(); NEXT; }
1228
		case 0x1f: { II ii = rr_R<A>(); NEXT; }
1229
		case 0x1e: { II ii = rr_xhl();  NEXT; }
1230
		case 0x20: { II ii = sla_R<B>(); NEXT; }
1231
		case 0x21: { II ii = sla_R<C>(); NEXT; }
1232
		case 0x22: { II ii = sla_R<D>(); NEXT; }
1233
		case 0x23: { II ii = sla_R<E>(); NEXT; }
1234
		case 0x24: { II ii = sla_R<H>(); NEXT; }
1235
		case 0x25: { II ii = sla_R<L>(); NEXT; }
1236
		case 0x27: { II ii = sla_R<A>(); NEXT; }
1237
		case 0x26: { II ii = sla_xhl();  NEXT; }
1238
		case 0x28: { II ii = sra_R<B>(); NEXT; }
1239
		case 0x29: { II ii = sra_R<C>(); NEXT; }
1240
		case 0x2a: { II ii = sra_R<D>(); NEXT; }
1241
		case 0x2b: { II ii = sra_R<E>(); NEXT; }
1242
		case 0x2c: { II ii = sra_R<H>(); NEXT; }
1243
		case 0x2d: { II ii = sra_R<L>(); NEXT; }
1244
		case 0x2f: { II ii = sra_R<A>(); NEXT; }
1245
		case 0x2e: { II ii = sra_xhl();  NEXT; }
1246
		case 0x30: { II ii = T::IS_R800 ? sla_R<B>() : sll_R<B>(); NEXT; }
1247
		case 0x31: { II ii = T::IS_R800 ? sla_R<C>() : sll_R<C>(); NEXT; }
1248
		case 0x32: { II ii = T::IS_R800 ? sla_R<D>() : sll_R<D>(); NEXT; }
1249
		case 0x33: { II ii = T::IS_R800 ? sla_R<E>() : sll_R<E>(); NEXT; }
1250
		case 0x34: { II ii = T::IS_R800 ? sla_R<H>() : sll_R<H>(); NEXT; }
1251
		case 0x35: { II ii = T::IS_R800 ? sla_R<L>() : sll_R<L>(); NEXT; }
1252
		case 0x37: { II ii = T::IS_R800 ? sla_R<A>() : sll_R<A>(); NEXT; }
1253
		case 0x36: { II ii = T::IS_R800 ? sla_xhl()  : sll_xhl();  NEXT; }
1254
		case 0x38: { II ii = srl_R<B>(); NEXT; }
1255
		case 0x39: { II ii = srl_R<C>(); NEXT; }
1256
		case 0x3a: { II ii = srl_R<D>(); NEXT; }
1257
		case 0x3b: { II ii = srl_R<E>(); NEXT; }
1258
		case 0x3c: { II ii = srl_R<H>(); NEXT; }
1259
		case 0x3d: { II ii = srl_R<L>(); NEXT; }
1260
		case 0x3f: { II ii = srl_R<A>(); NEXT; }
1261
		case 0x3e: { II ii = srl_xhl();  NEXT; }
1262
1263
		case 0x40: { II ii = bit_N_R<0,B>(); NEXT; }
1264
		case 0x41: { II ii = bit_N_R<0,C>(); NEXT; }
1265
		case 0x42: { II ii = bit_N_R<0,D>(); NEXT; }
1266
		case 0x43: { II ii = bit_N_R<0,E>(); NEXT; }
1267
		case 0x44: { II ii = bit_N_R<0,H>(); NEXT; }
1268
		case 0x45: { II ii = bit_N_R<0,L>(); NEXT; }
1269
		case 0x47: { II ii = bit_N_R<0,A>(); NEXT; }
1270
		case 0x48: { II ii = bit_N_R<1,B>(); NEXT; }
1271
		case 0x49: { II ii = bit_N_R<1,C>(); NEXT; }
1272
		case 0x4a: { II ii = bit_N_R<1,D>(); NEXT; }
1273
		case 0x4b: { II ii = bit_N_R<1,E>(); NEXT; }
1274
		case 0x4c: { II ii = bit_N_R<1,H>(); NEXT; }
1275
		case 0x4d: { II ii = bit_N_R<1,L>(); NEXT; }
1276
		case 0x4f: { II ii = bit_N_R<1,A>(); NEXT; }
1277
		case 0x50: { II ii = bit_N_R<2,B>(); NEXT; }
1278
		case 0x51: { II ii = bit_N_R<2,C>(); NEXT; }
1279
		case 0x52: { II ii = bit_N_R<2,D>(); NEXT; }
1280
		case 0x53: { II ii = bit_N_R<2,E>(); NEXT; }
1281
		case 0x54: { II ii = bit_N_R<2,H>(); NEXT; }
1282
		case 0x55: { II ii = bit_N_R<2,L>(); NEXT; }
1283
		case 0x57: { II ii = bit_N_R<2,A>(); NEXT; }
1284
		case 0x58: { II ii = bit_N_R<3,B>(); NEXT; }
1285
		case 0x59: { II ii = bit_N_R<3,C>(); NEXT; }
1286
		case 0x5a: { II ii = bit_N_R<3,D>(); NEXT; }
1287
		case 0x5b: { II ii = bit_N_R<3,E>(); NEXT; }
1288
		case 0x5c: { II ii = bit_N_R<3,H>(); NEXT; }
1289
		case 0x5d: { II ii = bit_N_R<3,L>(); NEXT; }
1290
		case 0x5f: { II ii = bit_N_R<3,A>(); NEXT; }
1291
		case 0x60: { II ii = bit_N_R<4,B>(); NEXT; }
1292
		case 0x61: { II ii = bit_N_R<4,C>(); NEXT; }
1293
		case 0x62: { II ii = bit_N_R<4,D>(); NEXT; }
1294
		case 0x63: { II ii = bit_N_R<4,E>(); NEXT; }
1295
		case 0x64: { II ii = bit_N_R<4,H>(); NEXT; }
1296
		case 0x65: { II ii = bit_N_R<4,L>(); NEXT; }
1297
		case 0x67: { II ii = bit_N_R<4,A>(); NEXT; }
1298
		case 0x68: { II ii = bit_N_R<5,B>(); NEXT; }
1299
		case 0x69: { II ii = bit_N_R<5,C>(); NEXT; }
1300
		case 0x6a: { II ii = bit_N_R<5,D>(); NEXT; }
1301
		case 0x6b: { II ii = bit_N_R<5,E>(); NEXT; }
1302
		case 0x6c: { II ii = bit_N_R<5,H>(); NEXT; }
1303
		case 0x6d: { II ii = bit_N_R<5,L>(); NEXT; }
1304
		case 0x6f: { II ii = bit_N_R<5,A>(); NEXT; }
1305
		case 0x70: { II ii = bit_N_R<6,B>(); NEXT; }
1306
		case 0x71: { II ii = bit_N_R<6,C>(); NEXT; }
1307
		case 0x72: { II ii = bit_N_R<6,D>(); NEXT; }
1308
		case 0x73: { II ii = bit_N_R<6,E>(); NEXT; }
1309
		case 0x74: { II ii = bit_N_R<6,H>(); NEXT; }
1310
		case 0x75: { II ii = bit_N_R<6,L>(); NEXT; }
1311
		case 0x77: { II ii = bit_N_R<6,A>(); NEXT; }
1312
		case 0x78: { II ii = bit_N_R<7,B>(); NEXT; }
1313
		case 0x79: { II ii = bit_N_R<7,C>(); NEXT; }
1314
		case 0x7a: { II ii = bit_N_R<7,D>(); NEXT; }
1315
		case 0x7b: { II ii = bit_N_R<7,E>(); NEXT; }
1316
		case 0x7c: { II ii = bit_N_R<7,H>(); NEXT; }
1317
		case 0x7d: { II ii = bit_N_R<7,L>(); NEXT; }
1318
		case 0x7f: { II ii = bit_N_R<7,A>(); NEXT; }
1319
		case 0x46: { II ii = bit_N_xhl<0>(); NEXT; }
1320
		case 0x4e: { II ii = bit_N_xhl<1>(); NEXT; }
1321
		case 0x56: { II ii = bit_N_xhl<2>(); NEXT; }
1322
		case 0x5e: { II ii = bit_N_xhl<3>(); NEXT; }
1323
		case 0x66: { II ii = bit_N_xhl<4>(); NEXT; }
1324
		case 0x6e: { II ii = bit_N_xhl<5>(); NEXT; }
1325
		case 0x76: { II ii = bit_N_xhl<6>(); NEXT; }
1326
		case 0x7e: { II ii = bit_N_xhl<7>(); NEXT; }
1327
1328
		case 0x80: { II ii = res_N_R<0,B>(); NEXT; }
1329
		case 0x81: { II ii = res_N_R<0,C>(); NEXT; }
1330
		case 0x82: { II ii = res_N_R<0,D>(); NEXT; }
1331
		case 0x83: { II ii = res_N_R<0,E>(); NEXT; }
1332
		case 0x84: { II ii = res_N_R<0,H>(); NEXT; }
1333
		case 0x85: { II ii = res_N_R<0,L>(); NEXT; }
1334
		case 0x87: { II ii = res_N_R<0,A>(); NEXT; }
1335
		case 0x88: { II ii = res_N_R<1,B>(); NEXT; }
1336
		case 0x89: { II ii = res_N_R<1,C>(); NEXT; }
1337
		case 0x8a: { II ii = res_N_R<1,D>(); NEXT; }
1338
		case 0x8b: { II ii = res_N_R<1,E>(); NEXT; }
1339
		case 0x8c: { II ii = res_N_R<1,H>(); NEXT; }
1340
		case 0x8d: { II ii = res_N_R<1,L>(); NEXT; }
1341
		case 0x8f: { II ii = res_N_R<1,A>(); NEXT; }
1342
		case 0x90: { II ii = res_N_R<2,B>(); NEXT; }
1343
		case 0x91: { II ii = res_N_R<2,C>(); NEXT; }
1344
		case 0x92: { II ii = res_N_R<2,D>(); NEXT; }
1345
		case 0x93: { II ii = res_N_R<2,E>(); NEXT; }
1346
		case 0x94: { II ii = res_N_R<2,H>(); NEXT; }
1347
		case 0x95: { II ii = res_N_R<2,L>(); NEXT; }
1348
		case 0x97: { II ii = res_N_R<2,A>(); NEXT; }
1349
		case 0x98: { II ii = res_N_R<3,B>(); NEXT; }
1350
		case 0x99: { II ii = res_N_R<3,C>(); NEXT; }
1351
		case 0x9a: { II ii = res_N_R<3,D>(); NEXT; }
1352
		case 0x9b: { II ii = res_N_R<3,E>(); NEXT; }
1353
		case 0x9c: { II ii = res_N_R<3,H>(); NEXT; }
1354
		case 0x9d: { II ii = res_N_R<3,L>(); NEXT; }
1355
		case 0x9f: { II ii = res_N_R<3,A>(); NEXT; }
1356
		case 0xa0: { II ii = res_N_R<4,B>(); NEXT; }
1357
		case 0xa1: { II ii = res_N_R<4,C>(); NEXT; }
1358
		case 0xa2: { II ii = res_N_R<4,D>(); NEXT; }
1359
		case 0xa3: { II ii = res_N_R<4,E>(); NEXT; }
1360
		case 0xa4: { II ii = res_N_R<4,H>(); NEXT; }
1361
		case 0xa5: { II ii = res_N_R<4,L>(); NEXT; }
1362
		case 0xa7: { II ii = res_N_R<4,A>(); NEXT; }
1363
		case 0xa8: { II ii = res_N_R<5,B>(); NEXT; }
1364
		case 0xa9: { II ii = res_N_R<5,C>(); NEXT; }
1365
		case 0xaa: { II ii = res_N_R<5,D>(); NEXT; }
1366
		case 0xab: { II ii = res_N_R<5,E>(); NEXT; }
1367
		case 0xac: { II ii = res_N_R<5,H>(); NEXT; }
1368
		case 0xad: { II ii = res_N_R<5,L>(); NEXT; }
1369
		case 0xaf: { II ii = res_N_R<5,A>(); NEXT; }
1370
		case 0xb0: { II ii = res_N_R<6,B>(); NEXT; }
1371
		case 0xb1: { II ii = res_N_R<6,C>(); NEXT; }
1372
		case 0xb2: { II ii = res_N_R<6,D>(); NEXT; }
1373
		case 0xb3: { II ii = res_N_R<6,E>(); NEXT; }
1374
		case 0xb4: { II ii = res_N_R<6,H>(); NEXT; }
1375
		case 0xb5: { II ii = res_N_R<6,L>(); NEXT; }
1376
		case 0xb7: { II ii = res_N_R<6,A>(); NEXT; }
1377
		case 0xb8: { II ii = res_N_R<7,B>(); NEXT; }
1378
		case 0xb9: { II ii = res_N_R<7,C>(); NEXT; }
1379
		case 0xba: { II ii = res_N_R<7,D>(); NEXT; }
1380
		case 0xbb: { II ii = res_N_R<7,E>(); NEXT; }
1381
		case 0xbc: { II ii = res_N_R<7,H>(); NEXT; }
1382
		case 0xbd: { II ii = res_N_R<7,L>(); NEXT; }
1383
		case 0xbf: { II ii = res_N_R<7,A>(); NEXT; }
1384
		case 0x86: { II ii = res_N_xhl<0>(); NEXT; }
1385
		case 0x8e: { II ii = res_N_xhl<1>(); NEXT; }
1386
		case 0x96: { II ii = res_N_xhl<2>(); NEXT; }
1387
		case 0x9e: { II ii = res_N_xhl<3>(); NEXT; }
1388
		case 0xa6: { II ii = res_N_xhl<4>(); NEXT; }
1389
		case 0xae: { II ii = res_N_xhl<5>(); NEXT; }
1390
		case 0xb6: { II ii = res_N_xhl<6>(); NEXT; }
1391
		case 0xbe: { II ii = res_N_xhl<7>(); NEXT; }
1392
1393
		case 0xc0: { II ii = set_N_R<0,B>(); NEXT; }
1394
		case 0xc1: { II ii = set_N_R<0,C>(); NEXT; }
1395
		case 0xc2: { II ii = set_N_R<0,D>(); NEXT; }
1396
		case 0xc3: { II ii = set_N_R<0,E>(); NEXT; }
1397
		case 0xc4: { II ii = set_N_R<0,H>(); NEXT; }
1398
		case 0xc5: { II ii = set_N_R<0,L>(); NEXT; }
1399
		case 0xc7: { II ii = set_N_R<0,A>(); NEXT; }
1400
		case 0xc8: { II ii = set_N_R<1,B>(); NEXT; }
1401
		case 0xc9: { II ii = set_N_R<1,C>(); NEXT; }
1402
		case 0xca: { II ii = set_N_R<1,D>(); NEXT; }
1403
		case 0xcb: { II ii = set_N_R<1,E>(); NEXT; }
1404
		case 0xcc: { II ii = set_N_R<1,H>(); NEXT; }
1405
		case 0xcd: { II ii = set_N_R<1,L>(); NEXT; }
1406
		case 0xcf: { II ii = set_N_R<1,A>(); NEXT; }
1407
		case 0xd0: { II ii = set_N_R<2,B>(); NEXT; }
1408
		case 0xd1: { II ii = set_N_R<2,C>(); NEXT; }
1409
		case 0xd2: { II ii = set_N_R<2,D>(); NEXT; }
1410
		case 0xd3: { II ii = set_N_R<2,E>(); NEXT; }
1411
		case 0xd4: { II ii = set_N_R<2,H>(); NEXT; }
1412
		case 0xd5: { II ii = set_N_R<2,L>(); NEXT; }
1413
		case 0xd7: { II ii = set_N_R<2,A>(); NEXT; }
1414
		case 0xd8: { II ii = set_N_R<3,B>(); NEXT; }
1415
		case 0xd9: { II ii = set_N_R<3,C>(); NEXT; }
1416
		case 0xda: { II ii = set_N_R<3,D>(); NEXT; }
1417
		case 0xdb: { II ii = set_N_R<3,E>(); NEXT; }
1418
		case 0xdc: { II ii = set_N_R<3,H>(); NEXT; }
1419
		case 0xdd: { II ii = set_N_R<3,L>(); NEXT; }
1420
		case 0xdf: { II ii = set_N_R<3,A>(); NEXT; }
1421
		case 0xe0: { II ii = set_N_R<4,B>(); NEXT; }
1422
		case 0xe1: { II ii = set_N_R<4,C>(); NEXT; }
1423
		case 0xe2: { II ii = set_N_R<4,D>(); NEXT; }
1424
		case 0xe3: { II ii = set_N_R<4,E>(); NEXT; }
1425
		case 0xe4: { II ii = set_N_R<4,H>(); NEXT; }
1426
		case 0xe5: { II ii = set_N_R<4,L>(); NEXT; }
1427
		case 0xe7: { II ii = set_N_R<4,A>(); NEXT; }
1428
		case 0xe8: { II ii = set_N_R<5,B>(); NEXT; }
1429
		case 0xe9: { II ii = set_N_R<5,C>(); NEXT; }
1430
		case 0xea: { II ii = set_N_R<5,D>(); NEXT; }
1431
		case 0xeb: { II ii = set_N_R<5,E>(); NEXT; }
1432
		case 0xec: { II ii = set_N_R<5,H>(); NEXT; }
1433
		case 0xed: { II ii = set_N_R<5,L>(); NEXT; }
1434
		case 0xef: { II ii = set_N_R<5,A>(); NEXT; }
1435
		case 0xf0: { II ii = set_N_R<6,B>(); NEXT; }
1436
		case 0xf1: { II ii = set_N_R<6,C>(); NEXT; }
1437
		case 0xf2: { II ii = set_N_R<6,D>(); NEXT; }
1438
		case 0xf3: { II ii = set_N_R<6,E>(); NEXT; }
1439
		case 0xf4: { II ii = set_N_R<6,H>(); NEXT; }
1440
		case 0xf5: { II ii = set_N_R<6,L>(); NEXT; }
1441
		case 0xf7: { II ii = set_N_R<6,A>(); NEXT; }
1442
		case 0xf8: { II ii = set_N_R<7,B>(); NEXT; }
1443
		case 0xf9: { II ii = set_N_R<7,C>(); NEXT; }
1444
		case 0xfa: { II ii = set_N_R<7,D>(); NEXT; }
1445
		case 0xfb: { II ii = set_N_R<7,E>(); NEXT; }
1446
		case 0xfc: { II ii = set_N_R<7,H>(); NEXT; }
1447
		case 0xfd: { II ii = set_N_R<7,L>(); NEXT; }
1448
		case 0xff: { II ii = set_N_R<7,A>(); NEXT; }
1449
		case 0xc6: { II ii = set_N_xhl<0>(); NEXT; }
1450
		case 0xce: { II ii = set_N_xhl<1>(); NEXT; }
1451
		case 0xd6: { II ii = set_N_xhl<2>(); NEXT; }
1452
		case 0xde: { II ii = set_N_xhl<3>(); NEXT; }
1453
		case 0xe6: { II ii = set_N_xhl<4>(); NEXT; }
1454
		case 0xee: { II ii = set_N_xhl<5>(); NEXT; }
1455
		case 0xf6: { II ii = set_N_xhl<6>(); NEXT; }
1456
		case 0xfe: { II ii = set_N_xhl<7>(); NEXT; }
1457
		default: UNREACHABLE;
1458
	}
1459
}
1460
CASE(ED) {
1461
	setPC(getPC() + 1); // M1 cycle at this point
1462
	uint8_t ed_opcode = RDMEM_OPCODE<0>(T::CC_PREFIX);
1463
	incR(1);
1464
	switch (ed_opcode) {
1465
		case 0x00: case 0x01: case 0x02: case 0x03:
1466
		case 0x04: case 0x05: case 0x06: case 0x07:
1467
		case 0x08: case 0x09: case 0x0a: case 0x0b:
1468
		case 0x0c: case 0x0d: case 0x0e: case 0x0f:
1469
		case 0x10: case 0x11: case 0x12: case 0x13:
1470
		case 0x14: case 0x15: case 0x16: case 0x17:
1471
		case 0x18: case 0x19: case 0x1a: case 0x1b:
1472
		case 0x1c: case 0x1d: case 0x1e: case 0x1f:
1473
		case 0x20: case 0x21: case 0x22: case 0x23:
1474
		case 0x24: case 0x25: case 0x26: case 0x27:
1475
		case 0x28: case 0x29: case 0x2a: case 0x2b:
1476
		case 0x2c: case 0x2d: case 0x2e: case 0x2f:
1477
		case 0x30: case 0x31: case 0x32: case 0x33:
1478
		case 0x34: case 0x35: case 0x36: case 0x37:
1479
		case 0x38: case 0x39: case 0x3a: case 0x3b:
1480
		case 0x3c: case 0x3d: case 0x3e: case 0x3f:
1481
1482
		case 0x77: case 0x7f:
1483
1484
		case 0x80: case 0x81: case 0x82: case 0x83:
1485
		case 0x84: case 0x85: case 0x86: case 0x87:
1486
		case 0x88: case 0x89: case 0x8a: case 0x8b:
1487
		case 0x8c: case 0x8d: case 0x8e: case 0x8f:
1488
		case 0x90: case 0x91: case 0x92: case 0x93:
1489
		case 0x94: case 0x95: case 0x96: case 0x97:
1490
		case 0x98: case 0x99: case 0x9a: case 0x9b:
1491
		case 0x9c: case 0x9d: case 0x9e: case 0x9f:
1492
		case 0xa4: case 0xa5: case 0xa6: case 0xa7:
1493
		case 0xac: case 0xad: case 0xae: case 0xaf:
1494
		case 0xb4: case 0xb5: case 0xb6: case 0xb7:
1495
		case 0xbc: case 0xbd: case 0xbe: case 0xbf:
1496
1497
		case 0xc0:            case 0xc2:
1498
		case 0xc4: case 0xc5: case 0xc6: case 0xc7:
1499
		case 0xc8: case 0xca: case 0xcb:
1500
		case 0xcc: case 0xcd: case 0xce: case 0xcf:
1501
		case 0xd0:            case 0xd2: case 0xd3:
1502
		case 0xd4: case 0xd5: case 0xd6: case 0xd7:
1503
		case 0xd8:            case 0xda: case 0xdb:
1504
		case 0xdc: case 0xdd: case 0xde: case 0xdf:
1505
		case 0xe0: case 0xe1: case 0xe2: case 0xe3:
1506
		case 0xe4: case 0xe5: case 0xe6: case 0xe7:
1507
		case 0xe8: case 0xe9: case 0xea: case 0xeb:
1508
		case 0xec: case 0xed: case 0xee: case 0xef:
1509
		case 0xf0: case 0xf1: case 0xf2:
1510
		case 0xf4: case 0xf5: case 0xf6: case 0xf7:
1511
		case 0xf8: case 0xf9: case 0xfa: case 0xfb:
1512
		case 0xfc: case 0xfd: case 0xfe: case 0xff:
1513
		           { II ii = nop(); NEXT; }
1514
1515
		case 0x40: { II ii = in_R_c<B>(); NEXT; }
1516
		case 0x48: { II ii = in_R_c<C>(); NEXT; }
1517
		case 0x50: { II ii = in_R_c<D>(); NEXT; }
1518
		case 0x58: { II ii = in_R_c<E>(); NEXT; }
1519
		case 0x60: { II ii = in_R_c<H>(); NEXT; }
1520
		case 0x68: { II ii = in_R_c<L>(); NEXT; }
1521
		case 0x70: { II ii = in_R_c<DUMMY>(); NEXT; }
1522
		case 0x78: { II ii = in_R_c<A>(); NEXT; }
1523
1524
		case 0x41: { II ii = out_c_R<B>(); NEXT; }
1525
		case 0x49: { II ii = out_c_R<C>(); NEXT; }
1526
		case 0x51: { II ii = out_c_R<D>(); NEXT; }
1527
		case 0x59: { II ii = out_c_R<E>(); NEXT; }
1528
		case 0x61: { II ii = out_c_R<H>(); NEXT; }
1529
		case 0x69: { II ii = out_c_R<L>(); NEXT; }
1530
		case 0x71: { II ii = out_c_0();    NEXT; }
1531
		case 0x79: { II ii = out_c_R<A>(); NEXT; }
1532
1533
		case 0x42: { II ii = sbc_hl_SS<BC>(); NEXT; }
1534
		case 0x52: { II ii = sbc_hl_SS<DE>(); NEXT; }
1535
		case 0x62: { II ii = sbc_hl_hl    (); NEXT; }
1536
		case 0x72: { II ii = sbc_hl_SS<SP>(); NEXT; }
1537
1538
		case 0x4a: { II ii = adc_hl_SS<BC>(); NEXT; }
1539
		case 0x5a: { II ii = adc_hl_SS<DE>(); NEXT; }
1540
		case 0x6a: { II ii = adc_hl_hl    (); NEXT; }
1541
		case 0x7a: { II ii = adc_hl_SS<SP>(); NEXT; }
1542
1543
		case 0x43: { II ii = ld_xword_SS_ED<BC>(); NEXT; }
1544
		case 0x53: { II ii = ld_xword_SS_ED<DE>(); NEXT; }
1545
		case 0x63: { II ii = ld_xword_SS_ED<HL>(); NEXT; }
1546
		case 0x73: { II ii = ld_xword_SS_ED<SP>(); NEXT; }
1547
1548
		case 0x4b: { II ii = ld_SS_xword_ED<BC>(); NEXT; }
1549
		case 0x5b: { II ii = ld_SS_xword_ED<DE>(); NEXT; }
1550
		case 0x6b: { II ii = ld_SS_xword_ED<HL>(); NEXT; }
1551
		case 0x7b: { II ii = ld_SS_xword_ED<SP>(); NEXT; }
1552
1553
		case 0x47: { II ii = ld_i_a(); NEXT; }
1554
		case 0x4f: { II ii = ld_r_a(); NEXT; }
1555
		case 0x57: { II ii = ld_a_IR<REG_I>(); if (T::IS_R800) { NEXT; } else { NEXT_STOP; }}
1556
		case 0x5f: { II ii = ld_a_IR<REG_R>(); if (T::IS_R800) { NEXT; } else { NEXT_STOP; }}
1557
1558
		case 0x67: { II ii = rrd(); NEXT; }
1559
		case 0x6f: { II ii = rld(); NEXT; }
1560
1561
		case 0x45: case 0x4d: case 0x55: case 0x5d:
1562
		case 0x65: case 0x6d: case 0x75: case 0x7d:
1563
		           { II ii = retn(); NEXT_STOP; }
1564
		case 0x46: case 0x4e: case 0x66: case 0x6e:
1565
		           { II ii = im_N<0>(); NEXT; }
1566
		case 0x56: case 0x76:
1567
		           { II ii = im_N<1>(); NEXT; }
1568
		case 0x5e: case 0x7e:
1569
		           { II ii = im_N<2>(); NEXT; }
1570
		case 0x44: case 0x4c: case 0x54: case 0x5c:
1571
		case 0x64: case 0x6c: case 0x74: case 0x7c:
1572
		           { II ii = neg(); NEXT; }
1573
1574
		case 0xa0: { II ii = ldi();  NEXT; }
1575
		case 0xa1: { II ii = cpi();  NEXT; }
1576
		case 0xa2: { II ii = ini();  NEXT; }
1577
		case 0xa3: { II ii = outi(); NEXT; }
1578
		case 0xa8: { II ii = ldd();  NEXT; }
1579
		case 0xa9: { II ii = cpd();  NEXT; }
1580
		case 0xaa: { II ii = ind();  NEXT; }
1581
		case 0xab: { II ii = outd(); NEXT; }
1582
		case 0xb0: { II ii = ldir(); NEXT; }
1583
		case 0xb1: { II ii = cpir(); NEXT; }
1584
		case 0xb2: { II ii = inir(); NEXT; }
1585
		case 0xb3: { II ii = otir(); NEXT; }
1586
		case 0xb8: { II ii = lddr(); NEXT; }
1587
		case 0xb9: { II ii = cpdr(); NEXT; }
1588
		case 0xba: { II ii = indr(); NEXT; }
1589
		case 0xbb: { II ii = otdr(); NEXT; }
1590
1591
		case 0xc1: { II ii = T::IS_R800 ? mulub_a_R<B>() : nop(); NEXT; }
1592
		case 0xc9: { II ii = T::IS_R800 ? mulub_a_R<C>() : nop(); NEXT; }
1593
		case 0xd1: { II ii = T::IS_R800 ? mulub_a_R<D>() : nop(); NEXT; }
1594
		case 0xd9: { II ii = T::IS_R800 ? mulub_a_R<E>() : nop(); NEXT; }
1595
		case 0xc3: { II ii = T::IS_R800 ? muluw_hl_SS<BC>() : nop(); NEXT; }
1596
		case 0xf3: { II ii = T::IS_R800 ? muluw_hl_SS<SP>() : nop(); NEXT; }
1597
		default: UNREACHABLE;
1598
	}
1599
}
1600
MAYBE_UNUSED_LABEL opDD_2:
1601
CASE(DD) {
1602
	setPC(getPC() + 1); // M1 cycle at this point
1603
	uint8_t opcodeDD = RDMEM_OPCODE<0>(T::CC_DD + T::CC_MAIN);
1604
	incR(1);
1605
	switch (opcodeDD) {
1606
		case 0x00: // nop();
1607
		case 0x01: // ld_bc_word();
1608
		case 0x02: // ld_xbc_a();
1609
		case 0x03: // inc_bc();
1610
		case 0x04: // inc_b();
1611
		case 0x05: // dec_b();
1612
		case 0x06: // ld_b_byte();
1613
		case 0x07: // rlca();
1614
		case 0x08: // ex_af_af();
1615
		case 0x0a: // ld_a_xbc();
1616
		case 0x0b: // dec_bc();
1617
		case 0x0c: // inc_c();
1618
		case 0x0d: // dec_c();
1619
		case 0x0e: // ld_c_byte();
1620
		case 0x0f: // rrca();
1621
		case 0x10: // djnz();
1622
		case 0x11: // ld_de_word();
1623
		case 0x12: // ld_xde_a();
1624
		case 0x13: // inc_de();
1625
		case 0x14: // inc_d();
1626
		case 0x15: // dec_d();
1627
		case 0x16: // ld_d_byte();
1628
		case 0x17: // rla();
1629
		case 0x18: // jr();
1630
		case 0x1a: // ld_a_xde();
1631
		case 0x1b: // dec_de();
1632
		case 0x1c: // inc_e();
1633
		case 0x1d: // dec_e();
1634
		case 0x1e: // ld_e_byte();
1635
		case 0x1f: // rra();
1636
		case 0x20: // jr_nz();
1637
		case 0x27: // daa();
1638
		case 0x28: // jr_z();
1639
		case 0x2f: // cpl();
1640
		case 0x30: // jr_nc();
1641
		case 0x31: // ld_sp_word();
1642
		case 0x32: // ld_xbyte_a();
1643
		case 0x33: // inc_sp();
1644
		case 0x37: // scf();
1645
		case 0x38: // jr_c();
1646
		case 0x3a: // ld_a_xbyte();
1647
		case 0x3b: // dec_sp();
1648
		case 0x3c: // inc_a();
1649
		case 0x3d: // dec_a();
1650
		case 0x3e: // ld_a_byte();
1651
		case 0x3f: // ccf();
1652
1653
		case 0x40: // ld_b_b();
1654
		case 0x41: // ld_b_c();
1655
		case 0x42: // ld_b_d();
1656
		case 0x43: // ld_b_e();
1657
		case 0x47: // ld_b_a();
1658
		case 0x48: // ld_c_b();
1659
		case 0x49: // ld_c_c();
1660
		case 0x4a: // ld_c_d();
1661
		case 0x4b: // ld_c_e();
1662
		case 0x4f: // ld_c_a();
1663
		case 0x50: // ld_d_b();
1664
		case 0x51: // ld_d_c();
1665
		case 0x52: // ld_d_d();
1666
		case 0x53: // ld_d_e();
1667
		case 0x57: // ld_d_a();
1668
		case 0x58: // ld_e_b();
1669
		case 0x59: // ld_e_c();
1670
		case 0x5a: // ld_e_d();
1671
		case 0x5b: // ld_e_e();
1672
		case 0x5f: // ld_e_a();
1673
		case 0x64: // ld_ixh_ixh(); == nop
1674
		case 0x6d: // ld_ixl_ixl(); == nop
1675
		case 0x76: // halt();
1676
		case 0x78: // ld_a_b();
1677
		case 0x79: // ld_a_c();
1678
		case 0x7a: // ld_a_d();
1679
		case 0x7b: // ld_a_e();
1680
		case 0x7f: // ld_a_a();
1681
1682
		case 0x80: // add_a_b();
1683
		case 0x81: // add_a_c();
1684
		case 0x82: // add_a_d();
1685
		case 0x83: // add_a_e();
1686
		case 0x87: // add_a_a();
1687
		case 0x88: // adc_a_b();
1688
		case 0x89: // adc_a_c();
1689
		case 0x8a: // adc_a_d();
1690
		case 0x8b: // adc_a_e();
1691
		case 0x8f: // adc_a_a();
1692
		case 0x90: // sub_b();
1693
		case 0x91: // sub_c();
1694
		case 0x92: // sub_d();
1695
		case 0x93: // sub_e();
1696
		case 0x97: // sub_a();
1697
		case 0x98: // sbc_a_b();
1698
		case 0x99: // sbc_a_c();
1699
		case 0x9a: // sbc_a_d();
1700
		case 0x9b: // sbc_a_e();
1701
		case 0x9f: // sbc_a_a();
1702
		case 0xa0: // and_b();
1703
		case 0xa1: // and_c();
1704
		case 0xa2: // and_d();
1705
		case 0xa3: // and_e();
1706
		case 0xa7: // and_a();
1707
		case 0xa8: // xor_b();
1708
		case 0xa9: // xor_c();
1709
		case 0xaa: // xor_d();
1710
		case 0xab: // xor_e();
1711
		case 0xaf: // xor_a();
1712
		case 0xb0: // or_b();
1713
		case 0xb1: // or_c();
1714
		case 0xb2: // or_d();
1715
		case 0xb3: // or_e();
1716
		case 0xb7: // or_a();
1717
		case 0xb8: // cp_b();
1718
		case 0xb9: // cp_c();
1719
		case 0xba: // cp_d();
1720
		case 0xbb: // cp_e();
1721
		case 0xbf: // cp_a();
1722
1723
		case 0xc0: // ret_nz();
1724
		case 0xc1: // pop_bc();
1725
		case 0xc2: // jp_nz();
1726
		case 0xc3: // jp();
1727
		case 0xc4: // call_nz();
1728
		case 0xc5: // push_bc();
1729
		case 0xc6: // add_a_byte();
1730
		case 0xc7: // rst_00();
1731
		case 0xc8: // ret_z();
1732
		case 0xc9: // ret();
1733
		case 0xca: // jp_z();
1734
		case 0xcc: // call_z();
1735
		case 0xcd: // call();
1736
		case 0xce: // adc_a_byte();
1737
		case 0xcf: // rst_08();
1738
		case 0xd0: // ret_nc();
1739
		case 0xd1: // pop_de();
1740
		case 0xd2: // jp_nc();
1741
		case 0xd3: // out_byte_a();
1742
		case 0xd4: // call_nc();
1743
		case 0xd5: // push_de();
1744
		case 0xd6: // sub_byte();
1745
		case 0xd7: // rst_10();
1746
		case 0xd8: // ret_c();
1747
		case 0xd9: // exx();
1748
		case 0xda: // jp_c();
1749
		case 0xdb: // in_a_byte();
1750
		case 0xdc: // call_c();
1751
		case 0xde: // sbc_a_byte();
1752
		case 0xdf: // rst_18();
1753
		case 0xe0: // ret_po();
1754
		case 0xe2: // jp_po();
1755
		case 0xe4: // call_po();
1756
		case 0xe6: // and_byte();
1757
		case 0xe7: // rst_20();
1758
		case 0xe8: // ret_pe();
1759
		case 0xea: // jp_pe();
1760
		case 0xeb: // ex_de_hl();
1761
		case 0xec: // call_pe();
1762
		case 0xed: // ed();
1763
		case 0xee: // xor_byte();
1764
		case 0xef: // rst_28();
1765
		case 0xf0: // ret_p();
1766
		case 0xf1: // pop_af();
1767
		case 0xf2: // jp_p();
1768
		case 0xf3: // di();
1769
		case 0xf4: // call_p();
1770
		case 0xf5: // push_af();
1771
		case 0xf6: // or_byte();
1772
		case 0xf7: // rst_30();
1773
		case 0xf8: // ret_m();
1774
		case 0xfa: // jp_m();
1775
		case 0xfb: // ei();
1776
		case 0xfc: // call_m();
1777
		case 0xfe: // cp_byte();
1778
		case 0xff: // rst_38();
1779
			if constexpr (T::IS_R800) {
1780
				II ii = nop<T::CC_DD>(); NEXT;
1781
			} else {
1782
				T::add(T::CC_DD);
1783
				#ifdef USE_COMPUTED_GOTO
1784
				goto *(opcodeTable[opcodeDD]);
1785
				#else
1786
				opcodeMain = opcodeDD;
1787
				goto switchOpcode;
1788
				#endif
1789
			}
1790
1791
		case 0x09: { II ii = add_SS_TT<IX,BC,T::CC_DD>(); NEXT; }
1792
		case 0x19: { II ii = add_SS_TT<IX,DE,T::CC_DD>(); NEXT; }
1793
		case 0x29: { II ii = add_SS_SS<IX   ,T::CC_DD>(); NEXT; }
1794
		case 0x39: { II ii = add_SS_TT<IX,SP,T::CC_DD>(); NEXT; }
1795
		case 0x21: { II ii = ld_SS_word<IX,T::CC_DD>();  NEXT; }
1796
		case 0x22: { II ii = ld_xword_SS<IX,T::CC_DD>(); NEXT; }
1797
		case 0x2a: { II ii = ld_SS_xword<IX,T::CC_DD>(); NEXT; }
1798
		case 0x23: { II ii = inc_SS<IX,T::CC_DD>(); NEXT; }
1799
		case 0x2b: { II ii = dec_SS<IX,T::CC_DD>(); NEXT; }
1800
		case 0x24: { II ii = inc_R<IXH,T::CC_DD>(); NEXT; }
1801
		case 0x2c: { II ii = inc_R<IXL,T::CC_DD>(); NEXT; }
1802
		case 0x25: { II ii = dec_R<IXH,T::CC_DD>(); NEXT; }
1803
		case 0x2d: { II ii = dec_R<IXL,T::CC_DD>(); NEXT; }
1804
		case 0x26: { II ii = ld_R_byte<IXH,T::CC_DD>(); NEXT; }
1805
		case 0x2e: { II ii = ld_R_byte<IXL,T::CC_DD>(); NEXT; }
1806
		case 0x34: { II ii = inc_xix<IX>(); NEXT; }
1807
		case 0x35: { II ii = dec_xix<IX>(); NEXT; }
1808
		case 0x36: { II ii = ld_xix_byte<IX>(); NEXT; }
1809
1810
		case 0x44: { II ii = ld_R_R<B,IXH,T::CC_DD>(); NEXT; }
1811
		case 0x45: { II ii = ld_R_R<B,IXL,T::CC_DD>(); NEXT; }
1812
		case 0x4c: { II ii = ld_R_R<C,IXH,T::CC_DD>(); NEXT; }
1813
		case 0x4d: { II ii = ld_R_R<C,IXL,T::CC_DD>(); NEXT; }
1814
		case 0x54: { II ii = ld_R_R<D,IXH,T::CC_DD>(); NEXT; }
1815
		case 0x55: { II ii = ld_R_R<D,IXL,T::CC_DD>(); NEXT; }
1816
		case 0x5c: { II ii = ld_R_R<E,IXH,T::CC_DD>(); NEXT; }
1817
		case 0x5d: { II ii = ld_R_R<E,IXL,T::CC_DD>(); NEXT; }
1818
		case 0x7c: { II ii = ld_R_R<A,IXH,T::CC_DD>(); NEXT; }
1819
		case 0x7d: { II ii = ld_R_R<A,IXL,T::CC_DD>(); NEXT; }
1820
		case 0x60: { II ii = ld_R_R<IXH,B,T::CC_DD>(); NEXT; }
1821
		case 0x61: { II ii = ld_R_R<IXH,C,T::CC_DD>(); NEXT; }
1822
		case 0x62: { II ii = ld_R_R<IXH,D,T::CC_DD>(); NEXT; }
1823
		case 0x63: { II ii = ld_R_R<IXH,E,T::CC_DD>(); NEXT; }
1824
		case 0x65: { II ii = ld_R_R<IXH,IXL,T::CC_DD>(); NEXT; }
1825
		case 0x67: { II ii = ld_R_R<IXH,A,T::CC_DD>(); NEXT; }
1826
		case 0x68: { II ii = ld_R_R<IXL,B,T::CC_DD>(); NEXT; }
1827
		case 0x69: { II ii = ld_R_R<IXL,C,T::CC_DD>(); NEXT; }
1828
		case 0x6a: { II ii = ld_R_R<IXL,D,T::CC_DD>(); NEXT; }
1829
		case 0x6b: { II ii = ld_R_R<IXL,E,T::CC_DD>(); NEXT; }
1830
		case 0x6c: { II ii = ld_R_R<IXL,IXH,T::CC_DD>(); NEXT; }
1831
		case 0x6f: { II ii = ld_R_R<IXL,A,T::CC_DD>(); NEXT; }
1832
		case 0x70: { II ii = ld_xix_R<IX,B>(); NEXT; }
1833
		case 0x71: { II ii = ld_xix_R<IX,C>(); NEXT; }
1834
		case 0x72: { II ii = ld_xix_R<IX,D>(); NEXT; }
1835
		case 0x73: { II ii = ld_xix_R<IX,E>(); NEXT; }
1836
		case 0x74: { II ii = ld_xix_R<IX,H>(); NEXT; }
1837
		case 0x75: { II ii = ld_xix_R<IX,L>(); NEXT; }
1838
		case 0x77: { II ii = ld_xix_R<IX,A>(); NEXT; }
1839
		case 0x46: { II ii = ld_R_xix<B,IX>(); NEXT; }
1840
		case 0x4e: { II ii = ld_R_xix<C,IX>(); NEXT; }
1841
		case 0x56: { II ii = ld_R_xix<D,IX>(); NEXT; }
1842
		case 0x5e: { II ii = ld_R_xix<E,IX>(); NEXT; }
1843
		case 0x66: { II ii = ld_R_xix<H,IX>(); NEXT; }
1844
		case 0x6e: { II ii = ld_R_xix<L,IX>(); NEXT; }
1845
		case 0x7e: { II ii = ld_R_xix<A,IX>(); NEXT; }
1846
1847
		case 0x84: { II ii = add_a_R<IXH,T::CC_DD>(); NEXT; }
1848
		case 0x85: { II ii = add_a_R<IXL,T::CC_DD>(); NEXT; }
1849
		case 0x86: { II ii = add_a_xix<IX>(); NEXT; }
1850
		case 0x8c: { II ii = adc_a_R<IXH,T::CC_DD>(); NEXT; }
1851
		case 0x8d: { II ii = adc_a_R<IXL,T::CC_DD>(); NEXT; }
1852
		case 0x8e: { II ii = adc_a_xix<IX>(); NEXT; }
1853
		case 0x94: { II ii = sub_R<IXH,T::CC_DD>(); NEXT; }
1854
		case 0x95: { II ii = sub_R<IXL,T::CC_DD>(); NEXT; }
1855
		case 0x96: { II ii = sub_xix<IX>(); NEXT; }
1856
		case 0x9c: { II ii = sbc_a_R<IXH,T::CC_DD>(); NEXT; }
1857
		case 0x9d: { II ii = sbc_a_R<IXL,T::CC_DD>(); NEXT; }
1858
		case 0x9e: { II ii = sbc_a_xix<IX>(); NEXT; }
1859
		case 0xa4: { II ii = and_R<IXH,T::CC_DD>(); NEXT; }
1860
		case 0xa5: { II ii = and_R<IXL,T::CC_DD>(); NEXT; }
1861
		case 0xa6: { II ii = and_xix<IX>(); NEXT; }
1862
		case 0xac: { II ii = xor_R<IXH,T::CC_DD>(); NEXT; }
1863
		case 0xad: { II ii = xor_R<IXL,T::CC_DD>(); NEXT; }
1864
		case 0xae: { II ii = xor_xix<IX>(); NEXT; }
1865
		case 0xb4: { II ii = or_R<IXH,T::CC_DD>(); NEXT; }
1866
		case 0xb5: { II ii = or_R<IXL,T::CC_DD>(); NEXT; }
1867
		case 0xb6: { II ii = or_xix<IX>(); NEXT; }
1868
		case 0xbc: { II ii = cp_R<IXH,T::CC_DD>(); NEXT; }
1869
		case 0xbd: { II ii = cp_R<IXL,T::CC_DD>(); NEXT; }
1870
		case 0xbe: { II ii = cp_xix<IX>(); NEXT; }
1871
1872
		case 0xe1: { II ii = pop_SS <IX,T::CC_DD>(); NEXT; }
1873
		case 0xe5: { II ii = push_SS<IX,T::CC_DD>(); NEXT; }
1874
		case 0xe3: { II ii = ex_xsp_SS<IX,T::CC_DD>(); NEXT; }
1875
		case 0xe9: { II ii = jp_SS<IX,T::CC_DD>(); NEXT; }
1876
		case 0xf9: { II ii = ld_sp_SS<IX,T::CC_DD>(); NEXT; }
1877
		case 0xcb: ixy = getIX(); goto xx_cb;
1878
		case 0xdd:
1879
			if constexpr (T::IS_R800) {
1880
				II ii = nop<T::CC_DD>(); NEXT;
1881
			} else {
1882
				T::add(T::CC_DD); goto opDD_2;
1883
			}
1884
		case 0xfd:
1885
			if constexpr (T::IS_R800) {
1886
				II ii = nop<T::CC_DD>(); NEXT;
1887
			} else {
1888
				T::add(T::CC_DD); goto opFD_2;
1889
			}
1890
		default: UNREACHABLE;
1891
	}
1892
}
1893
MAYBE_UNUSED_LABEL opFD_2:
1894
CASE(FD) {
1895
	setPC(getPC() + 1); // M1 cycle at this point
1896
	uint8_t opcodeFD = RDMEM_OPCODE<0>(T::CC_DD + T::CC_MAIN);
1897
	incR(1);
1898
	switch (opcodeFD) {
1899
		case 0x00: // nop();
1900
		case 0x01: // ld_bc_word();
1901
		case 0x02: // ld_xbc_a();
1902
		case 0x03: // inc_bc();
1903
		case 0x04: // inc_b();
1904
		case 0x05: // dec_b();
1905
		case 0x06: // ld_b_byte();
1906
		case 0x07: // rlca();
1907
		case 0x08: // ex_af_af();
1908
		case 0x0a: // ld_a_xbc();
1909
		case 0x0b: // dec_bc();
1910
		case 0x0c: // inc_c();
1911
		case 0x0d: // dec_c();
1912
		case 0x0e: // ld_c_byte();
1913
		case 0x0f: // rrca();
1914
		case 0x10: // djnz();
1915
		case 0x11: // ld_de_word();
1916
		case 0x12: // ld_xde_a();
1917
		case 0x13: // inc_de();
1918
		case 0x14: // inc_d();
1919
		case 0x15: // dec_d();
1920
		case 0x16: // ld_d_byte();
1921
		case 0x17: // rla();
1922
		case 0x18: // jr();
1923
		case 0x1a: // ld_a_xde();
1924
		case 0x1b: // dec_de();
1925
		case 0x1c: // inc_e();
1926
		case 0x1d: // dec_e();
1927
		case 0x1e: // ld_e_byte();
1928
		case 0x1f: // rra();
1929
		case 0x20: // jr_nz();
1930
		case 0x27: // daa();
1931
		case 0x28: // jr_z();
1932
		case 0x2f: // cpl();
1933
		case 0x30: // jr_nc();
1934
		case 0x31: // ld_sp_word();
1935
		case 0x32: // ld_xbyte_a();
1936
		case 0x33: // inc_sp();
1937
		case 0x37: // scf();
1938
		case 0x38: // jr_c();
1939
		case 0x3a: // ld_a_xbyte();
1940
		case 0x3b: // dec_sp();
1941
		case 0x3c: // inc_a();
1942
		case 0x3d: // dec_a();
1943
		case 0x3e: // ld_a_byte();
1944
		case 0x3f: // ccf();
1945
1946
		case 0x40: // ld_b_b();
1947
		case 0x41: // ld_b_c();
1948
		case 0x42: // ld_b_d();
1949
		case 0x43: // ld_b_e();
1950
		case 0x47: // ld_b_a();
1951
		case 0x48: // ld_c_b();
1952
		case 0x49: // ld_c_c();
1953
		case 0x4a: // ld_c_d();
1954
		case 0x4b: // ld_c_e();
1955
		case 0x4f: // ld_c_a();
1956
		case 0x50: // ld_d_b();
1957
		case 0x51: // ld_d_c();
1958
		case 0x52: // ld_d_d();
1959
		case 0x53: // ld_d_e();
1960
		case 0x57: // ld_d_a();
1961
		case 0x58: // ld_e_b();
1962
		case 0x59: // ld_e_c();
1963
		case 0x5a: // ld_e_d();
1964
		case 0x5b: // ld_e_e();
1965
		case 0x5f: // ld_e_a();
1966
		case 0x64: // ld_ixh_ixh(); == nop
1967
		case 0x6d: // ld_ixl_ixl(); == nop
1968
		case 0x76: // halt();
1969
		case 0x78: // ld_a_b();
1970
		case 0x79: // ld_a_c();
1971
		case 0x7a: // ld_a_d();
1972
		case 0x7b: // ld_a_e();
1973
		case 0x7f: // ld_a_a();
1974
1975
		case 0x80: // add_a_b();
1976
		case 0x81: // add_a_c();
1977
		case 0x82: // add_a_d();
1978
		case 0x83: // add_a_e();
1979
		case 0x87: // add_a_a();
1980
		case 0x88: // adc_a_b();
1981
		case 0x89: // adc_a_c();
1982
		case 0x8a: // adc_a_d();
1983
		case 0x8b: // adc_a_e();
1984
		case 0x8f: // adc_a_a();
1985
		case 0x90: // sub_b();
1986
		case 0x91: // sub_c();
1987
		case 0x92: // sub_d();
1988
		case 0x93: // sub_e();
1989
		case 0x97: // sub_a();
1990
		case 0x98: // sbc_a_b();
1991
		case 0x99: // sbc_a_c();
1992
		case 0x9a: // sbc_a_d();
1993
		case 0x9b: // sbc_a_e();
1994
		case 0x9f: // sbc_a_a();
1995
		case 0xa0: // and_b();
1996
		case 0xa1: // and_c();
1997
		case 0xa2: // and_d();
1998
		case 0xa3: // and_e();
1999
		case 0xa7: // and_a();
2000
		case 0xa8: // xor_b();
2001
		case 0xa9: // xor_c();
2002
		case 0xaa: // xor_d();
2003
		case 0xab: // xor_e();
2004
		case 0xaf: // xor_a();
2005
		case 0xb0: // or_b();
2006
		case 0xb1: // or_c();
2007
		case 0xb2: // or_d();
2008
		case 0xb3: // or_e();
2009
		case 0xb7: // or_a();
2010
		case 0xb8: // cp_b();
2011
		case 0xb9: // cp_c();
2012
		case 0xba: // cp_d();
2013
		case 0xbb: // cp_e();
2014
		case 0xbf: // cp_a();
2015
2016
		case 0xc0: // ret_nz();
2017
		case 0xc1: // pop_bc();
2018
		case 0xc2: // jp_nz();
2019
		case 0xc3: // jp();
2020
		case 0xc4: // call_nz();
2021
		case 0xc5: // push_bc();
2022
		case 0xc6: // add_a_byte();
2023
		case 0xc7: // rst_00();
2024
		case 0xc8: // ret_z();
2025
		case 0xc9: // ret();
2026
		case 0xca: // jp_z();
2027
		case 0xcc: // call_z();
2028
		case 0xcd: // call();
2029
		case 0xce: // adc_a_byte();
2030
		case 0xcf: // rst_08();
2031
		case 0xd0: // ret_nc();
2032
		case 0xd1: // pop_de();
2033
		case 0xd2: // jp_nc();
2034
		case 0xd3: // out_byte_a();
2035
		case 0xd4: // call_nc();
2036
		case 0xd5: // push_de();
2037
		case 0xd6: // sub_byte();
2038
		case 0xd7: // rst_10();
2039
		case 0xd8: // ret_c();
2040
		case 0xd9: // exx();
2041
		case 0xda: // jp_c();
2042
		case 0xdb: // in_a_byte();
2043
		case 0xdc: // call_c();
2044
		case 0xde: // sbc_a_byte();
2045
		case 0xdf: // rst_18();
2046
		case 0xe0: // ret_po();
2047
		case 0xe2: // jp_po();
2048
		case 0xe4: // call_po();
2049
		case 0xe6: // and_byte();
2050
		case 0xe7: // rst_20();
2051
		case 0xe8: // ret_pe();
2052
		case 0xea: // jp_pe();
2053
		case 0xeb: // ex_de_hl();
2054
		case 0xec: // call_pe();
2055
		case 0xed: // ed();
2056
		case 0xee: // xor_byte();
2057
		case 0xef: // rst_28();
2058
		case 0xf0: // ret_p();
2059
		case 0xf1: // pop_af();
2060
		case 0xf2: // jp_p();
2061
		case 0xf3: // di();
2062
		case 0xf4: // call_p();
2063
		case 0xf5: // push_af();
2064
		case 0xf6: // or_byte();
2065
		case 0xf7: // rst_30();
2066
		case 0xf8: // ret_m();
2067
		case 0xfa: // jp_m();
2068
		case 0xfb: // ei();
2069
		case 0xfc: // call_m();
2070
		case 0xfe: // cp_byte();
2071
		case 0xff: // rst_38();
2072
			if constexpr (T::IS_R800) {
2073
				II ii = nop<T::CC_DD>(); NEXT;
2074
			} else {
2075
				T::add(T::CC_DD);
2076
				#ifdef USE_COMPUTED_GOTO
2077
				goto *(opcodeTable[opcodeFD]);
2078
				#else
2079
				opcodeMain = opcodeFD;
2080
				goto switchOpcode;
2081
				#endif
2082
			}
2083
2084
		case 0x09: { II ii = add_SS_TT<IY,BC,T::CC_DD>(); NEXT; }
2085
		case 0x19: { II ii = add_SS_TT<IY,DE,T::CC_DD>(); NEXT; }
2086
		case 0x29: { II ii = add_SS_SS<IY   ,T::CC_DD>(); NEXT; }
2087
		case 0x39: { II ii = add_SS_TT<IY,SP,T::CC_DD>(); NEXT; }
2088
		case 0x21: { II ii = ld_SS_word<IY,T::CC_DD>();  NEXT; }
2089
		case 0x22: { II ii = ld_xword_SS<IY,T::CC_DD>(); NEXT; }
2090
		case 0x2a: { II ii = ld_SS_xword<IY,T::CC_DD>(); NEXT; }
2091
		case 0x23: { II ii = inc_SS<IY,T::CC_DD>(); NEXT; }
2092
		case 0x2b: { II ii = dec_SS<IY,T::CC_DD>(); NEXT; }
2093
		case 0x24: { II ii = inc_R<IYH,T::CC_DD>(); NEXT; }
2094
		case 0x2c: { II ii = inc_R<IYL,T::CC_DD>(); NEXT; }
2095
		case 0x25: { II ii = dec_R<IYH,T::CC_DD>(); NEXT; }
2096
		case 0x2d: { II ii = dec_R<IYL,T::CC_DD>(); NEXT; }
2097
		case 0x26: { II ii = ld_R_byte<IYH,T::CC_DD>(); NEXT; }
2098
		case 0x2e: { II ii = ld_R_byte<IYL,T::CC_DD>(); NEXT; }
2099
		case 0x34: { II ii = inc_xix<IY>(); NEXT; }
2100
		case 0x35: { II ii = dec_xix<IY>(); NEXT; }
2101
		case 0x36: { II ii = ld_xix_byte<IY>(); NEXT; }
2102
2103
		case 0x44: { II ii = ld_R_R<B,IYH,T::CC_DD>(); NEXT; }
2104
		case 0x45: { II ii = ld_R_R<B,IYL,T::CC_DD>(); NEXT; }
2105
		case 0x4c: { II ii = ld_R_R<C,IYH,T::CC_DD>(); NEXT; }
2106
		case 0x4d: { II ii = ld_R_R<C,IYL,T::CC_DD>(); NEXT; }
2107
		case 0x54: { II ii = ld_R_R<D,IYH,T::CC_DD>(); NEXT; }
2108
		case 0x55: { II ii = ld_R_R<D,IYL,T::CC_DD>(); NEXT; }
2109
		case 0x5c: { II ii = ld_R_R<E,IYH,T::CC_DD>(); NEXT; }
2110
		case 0x5d: { II ii = ld_R_R<E,IYL,T::CC_DD>(); NEXT; }
2111
		case 0x7c: { II ii = ld_R_R<A,IYH,T::CC_DD>(); NEXT; }
2112
		case 0x7d: { II ii = ld_R_R<A,IYL,T::CC_DD>(); NEXT; }
2113
		case 0x60: { II ii = ld_R_R<IYH,B,T::CC_DD>(); NEXT; }
2114
		case 0x61: { II ii = ld_R_R<IYH,C,T::CC_DD>(); NEXT; }
2115
		case 0x62: { II ii = ld_R_R<IYH,D,T::CC_DD>(); NEXT; }
2116
		case 0x63: { II ii = ld_R_R<IYH,E,T::CC_DD>(); NEXT; }
2117
		case 0x65: { II ii = ld_R_R<IYH,IYL,T::CC_DD>(); NEXT; }
2118
		case 0x67: { II ii = ld_R_R<IYH,A,T::CC_DD>(); NEXT; }
2119
		case 0x68: { II ii = ld_R_R<IYL,B,T::CC_DD>(); NEXT; }
2120
		case 0x69: { II ii = ld_R_R<IYL,C,T::CC_DD>(); NEXT; }
2121
		case 0x6a: { II ii = ld_R_R<IYL,D,T::CC_DD>(); NEXT; }
2122
		case 0x6b: { II ii = ld_R_R<IYL,E,T::CC_DD>(); NEXT; }
2123
		case 0x6c: { II ii = ld_R_R<IYL,IYH,T::CC_DD>(); NEXT; }
2124
		case 0x6f: { II ii = ld_R_R<IYL,A,T::CC_DD>(); NEXT; }
2125
		case 0x70: { II ii = ld_xix_R<IY,B>(); NEXT; }
2126
		case 0x71: { II ii = ld_xix_R<IY,C>(); NEXT; }
2127
		case 0x72: { II ii = ld_xix_R<IY,D>(); NEXT; }
2128
		case 0x73: { II ii = ld_xix_R<IY,E>(); NEXT; }
2129
		case 0x74: { II ii = ld_xix_R<IY,H>(); NEXT; }
2130
		case 0x75: { II ii = ld_xix_R<IY,L>(); NEXT; }
2131
		case 0x77: { II ii = ld_xix_R<IY,A>(); NEXT; }
2132
		case 0x46: { II ii = ld_R_xix<B,IY>(); NEXT; }
2133
		case 0x4e: { II ii = ld_R_xix<C,IY>(); NEXT; }
2134
		case 0x56: { II ii = ld_R_xix<D,IY>(); NEXT; }
2135
		case 0x5e: { II ii = ld_R_xix<E,IY>(); NEXT; }
2136
		case 0x66: { II ii = ld_R_xix<H,IY>(); NEXT; }
2137
		case 0x6e: { II ii = ld_R_xix<L,IY>(); NEXT; }
2138
		case 0x7e: { II ii = ld_R_xix<A,IY>(); NEXT; }
2139
2140
		case 0x84: { II ii = add_a_R<IYH,T::CC_DD>(); NEXT; }
2141
		case 0x85: { II ii = add_a_R<IYL,T::CC_DD>(); NEXT; }
2142
		case 0x86: { II ii = add_a_xix<IY>(); NEXT; }
2143
		case 0x8c: { II ii = adc_a_R<IYH,T::CC_DD>(); NEXT; }
2144
		case 0x8d: { II ii = adc_a_R<IYL,T::CC_DD>(); NEXT; }
2145
		case 0x8e: { II ii = adc_a_xix<IY>(); NEXT; }
2146
		case 0x94: { II ii = sub_R<IYH,T::CC_DD>(); NEXT; }
2147
		case 0x95: { II ii = sub_R<IYL,T::CC_DD>(); NEXT; }
2148
		case 0x96: { II ii = sub_xix<IY>(); NEXT; }
2149
		case 0x9c: { II ii = sbc_a_R<IYH,T::CC_DD>(); NEXT; }
2150
		case 0x9d: { II ii = sbc_a_R<IYL,T::CC_DD>(); NEXT; }
2151
		case 0x9e: { II ii = sbc_a_xix<IY>(); NEXT; }
2152
		case 0xa4: { II ii = and_R<IYH,T::CC_DD>(); NEXT; }
2153
		case 0xa5: { II ii = and_R<IYL,T::CC_DD>(); NEXT; }
2154
		case 0xa6: { II ii = and_xix<IY>(); NEXT; }
2155
		case 0xac: { II ii = xor_R<IYH,T::CC_DD>(); NEXT; }
2156
		case 0xad: { II ii = xor_R<IYL,T::CC_DD>(); NEXT; }
2157
		case 0xae: { II ii = xor_xix<IY>(); NEXT; }
2158
		case 0xb4: { II ii = or_R<IYH,T::CC_DD>(); NEXT; }
2159
		case 0xb5: { II ii = or_R<IYL,T::CC_DD>(); NEXT; }
2160
		case 0xb6: { II ii = or_xix<IY>(); NEXT; }
2161
		case 0xbc: { II ii = cp_R<IYH,T::CC_DD>(); NEXT; }
2162
		case 0xbd: { II ii = cp_R<IYL,T::CC_DD>(); NEXT; }
2163
		case 0xbe: { II ii = cp_xix<IY>(); NEXT; }
2164
2165
		case 0xe1: { II ii = pop_SS <IY,T::CC_DD>(); NEXT; }
2166
		case 0xe5: { II ii = push_SS<IY,T::CC_DD>(); NEXT; }
2167
		case 0xe3: { II ii = ex_xsp_SS<IY,T::CC_DD>(); NEXT; }
2168
		case 0xe9: { II ii = jp_SS<IY,T::CC_DD>(); NEXT; }
2169
		case 0xf9: { II ii = ld_sp_SS<IY,T::CC_DD>(); NEXT; }
2170
		case 0xcb: ixy = getIY(); goto xx_cb;
2171
		case 0xdd:
2172
			if constexpr (T::IS_R800) {
2173
				II ii = nop<T::CC_DD>(); NEXT;
2174
			} else {
2175
				T::add(T::CC_DD); goto opDD_2;
2176
			}
2177
		case 0xfd:
2178
			if constexpr (T::IS_R800) {
2179
				II ii = nop<T::CC_DD>(); NEXT;
2180
			} else {
2181
				T::add(T::CC_DD); goto opFD_2;
2182
			}
2183
		default: UNREACHABLE;
2184
	}
2185
}
2186
#ifndef USE_COMPUTED_GOTO
2187
	default: UNREACHABLE;
2188
}
2189
#endif
2190
2191
xx_cb: {
2192
		unsigned tmp = RD_WORD_PC<1>(T::CC_DD + T::CC_DD_CB);
2193
		auto ofst = narrow_cast<int8_t>(tmp & 0xFF);
2194
		unsigned addr = narrow_cast<uint16_t>(ixy + ofst);
2195
		auto xxcb_opcode = narrow_cast<uint8_t>(tmp >> 8);
2196
		switch (xxcb_opcode) {
2197
			case 0x00: { II ii = rlc_xix_R<B>(addr); NEXT; }
2198
			case 0x01: { II ii = rlc_xix_R<C>(addr); NEXT; }
2199
			case 0x02: { II ii = rlc_xix_R<D>(addr); NEXT; }
2200
			case 0x03: { II ii = rlc_xix_R<E>(addr); NEXT; }
2201
			case 0x04: { II ii = rlc_xix_R<H>(addr); NEXT; }
2202
			case 0x05: { II ii = rlc_xix_R<L>(addr); NEXT; }
2203
			case 0x06: { II ii = rlc_xix_R<DUMMY>(addr); NEXT; }
2204
			case 0x07: { II ii = rlc_xix_R<A>(addr); NEXT; }
2205
			case 0x08: { II ii = rrc_xix_R<B>(addr); NEXT; }
2206
			case 0x09: { II ii = rrc_xix_R<C>(addr); NEXT; }
2207
			case 0x0a: { II ii = rrc_xix_R<D>(addr); NEXT; }
2208
			case 0x0b: { II ii = rrc_xix_R<E>(addr); NEXT; }
2209
			case 0x0c: { II ii = rrc_xix_R<H>(addr); NEXT; }
2210
			case 0x0d: { II ii = rrc_xix_R<L>(addr); NEXT; }
2211
			case 0x0e: { II ii = rrc_xix_R<DUMMY>(addr); NEXT; }
2212
			case 0x0f: { II ii = rrc_xix_R<A>(addr); NEXT; }
2213
			case 0x10: { II ii = rl_xix_R<B>(addr); NEXT; }
2214
			case 0x11: { II ii = rl_xix_R<C>(addr); NEXT; }
2215
			case 0x12: { II ii = rl_xix_R<D>(addr); NEXT; }
2216
			case 0x13: { II ii = rl_xix_R<E>(addr); NEXT; }
2217
			case 0x14: { II ii = rl_xix_R<H>(addr); NEXT; }
2218
			case 0x15: { II ii = rl_xix_R<L>(addr); NEXT; }
2219
			case 0x16: { II ii = rl_xix_R<DUMMY>(addr); NEXT; }
2220
			case 0x17: { II ii = rl_xix_R<A>(addr); NEXT; }
2221
			case 0x18: { II ii = rr_xix_R<B>(addr); NEXT; }
2222
			case 0x19: { II ii = rr_xix_R<C>(addr); NEXT; }
2223
			case 0x1a: { II ii = rr_xix_R<D>(addr); NEXT; }
2224
			case 0x1b: { II ii = rr_xix_R<E>(addr); NEXT; }
2225
			case 0x1c: { II ii = rr_xix_R<H>(addr); NEXT; }
2226
			case 0x1d: { II ii = rr_xix_R<L>(addr); NEXT; }
2227
			case 0x1e: { II ii = rr_xix_R<DUMMY>(addr); NEXT; }
2228
			case 0x1f: { II ii = rr_xix_R<A>(addr); NEXT; }
2229
			case 0x20: { II ii = sla_xix_R<B>(addr); NEXT; }
2230
			case 0x21: { II ii = sla_xix_R<C>(addr); NEXT; }
2231
			case 0x22: { II ii = sla_xix_R<D>(addr); NEXT; }
2232
			case 0x23: { II ii = sla_xix_R<E>(addr); NEXT; }
2233
			case 0x24: { II ii = sla_xix_R<H>(addr); NEXT; }
2234
			case 0x25: { II ii = sla_xix_R<L>(addr); NEXT; }
2235
			case 0x26: { II ii = sla_xix_R<DUMMY>(addr); NEXT; }
2236
			case 0x27: { II ii = sla_xix_R<A>(addr); NEXT; }
2237
			case 0x28: { II ii = sra_xix_R<B>(addr); NEXT; }
2238
			case 0x29: { II ii = sra_xix_R<C>(addr); NEXT; }
2239
			case 0x2a: { II ii = sra_xix_R<D>(addr); NEXT; }
2240
			case 0x2b: { II ii = sra_xix_R<E>(addr); NEXT; }
2241
			case 0x2c: { II ii = sra_xix_R<H>(addr); NEXT; }
2242
			case 0x2d: { II ii = sra_xix_R<L>(addr); NEXT; }
2243
			case 0x2e: { II ii = sra_xix_R<DUMMY>(addr); NEXT; }
2244
			case 0x2f: { II ii = sra_xix_R<A>(addr); NEXT; }
2245
			case 0x30: { II ii = T::IS_R800 ? sll2() : sll_xix_R<B>(addr); NEXT; }
2246
			case 0x31: { II ii = T::IS_R800 ? sll2() : sll_xix_R<C>(addr); NEXT; }
2247
			case 0x32: { II ii = T::IS_R800 ? sll2() : sll_xix_R<D>(addr); NEXT; }
2248
			case 0x33: { II ii = T::IS_R800 ? sll2() : sll_xix_R<E>(addr); NEXT; }
2249
			case 0x34: { II ii = T::IS_R800 ? sll2() : sll_xix_R<H>(addr); NEXT; }
2250
			case 0x35: { II ii = T::IS_R800 ? sll2() : sll_xix_R<L>(addr); NEXT; }
2251
			case 0x36: { II ii = T::IS_R800 ? sll2() : sll_xix_R<DUMMY>(addr); NEXT; }
2252
			case 0x37: { II ii = T::IS_R800 ? sll2() : sll_xix_R<A>(addr); NEXT; }
2253
			case 0x38: { II ii = srl_xix_R<B>(addr); NEXT; }
2254
			case 0x39: { II ii = srl_xix_R<C>(addr); NEXT; }
2255
			case 0x3a: { II ii = srl_xix_R<D>(addr); NEXT; }
2256
			case 0x3b: { II ii = srl_xix_R<E>(addr); NEXT; }
2257
			case 0x3c: { II ii = srl_xix_R<H>(addr); NEXT; }
2258
			case 0x3d: { II ii = srl_xix_R<L>(addr); NEXT; }
2259
			case 0x3e: { II ii = srl_xix_R<DUMMY>(addr); NEXT; }
2260
			case 0x3f: { II ii = srl_xix_R<A>(addr); NEXT; }
2261
2262
			case 0x40: case 0x41: case 0x42: case 0x43:
2263
			case 0x44: case 0x45: case 0x46: case 0x47:
2264
			           { II ii = bit_N_xix<0>(addr); NEXT; }
2265
			case 0x48: case 0x49: case 0x4a: case 0x4b:
2266
			case 0x4c: case 0x4d: case 0x4e: case 0x4f:
2267
			           { II ii = bit_N_xix<1>(addr); NEXT; }
2268
			case 0x50: case 0x51: case 0x52: case 0x53:
2269
			case 0x54: case 0x55: case 0x56: case 0x57:
2270
			           { II ii = bit_N_xix<2>(addr); NEXT; }
2271
			case 0x58: case 0x59: case 0x5a: case 0x5b:
2272
			case 0x5c: case 0x5d: case 0x5e: case 0x5f:
2273
			           { II ii = bit_N_xix<3>(addr); NEXT; }
2274
			case 0x60: case 0x61: case 0x62: case 0x63:
2275
			case 0x64: case 0x65: case 0x66: case 0x67:
2276
			           { II ii = bit_N_xix<4>(addr); NEXT; }
2277
			case 0x68: case 0x69: case 0x6a: case 0x6b:
2278
			case 0x6c: case 0x6d: case 0x6e: case 0x6f:
2279
			           { II ii = bit_N_xix<5>(addr); NEXT; }
2280
			case 0x70: case 0x71: case 0x72: case 0x73:
2281
			case 0x74: case 0x75: case 0x76: case 0x77:
2282
			           { II ii = bit_N_xix<6>(addr); NEXT; }
2283
			case 0x78: case 0x79: case 0x7a: case 0x7b:
2284
			case 0x7c: case 0x7d: case 0x7e: case 0x7f:
2285
			           { II ii = bit_N_xix<7>(addr); NEXT; }
2286
2287
			case 0x80: { II ii = res_N_xix_R<0,B>(addr); NEXT; }
2288
			case 0x81: { II ii = res_N_xix_R<0,C>(addr); NEXT; }
2289
			case 0x82: { II ii = res_N_xix_R<0,D>(addr); NEXT; }
2290
			case 0x83: { II ii = res_N_xix_R<0,E>(addr); NEXT; }
2291
			case 0x84: { II ii = res_N_xix_R<0,H>(addr); NEXT; }
2292
			case 0x85: { II ii = res_N_xix_R<0,L>(addr); NEXT; }
2293
			case 0x87: { II ii = res_N_xix_R<0,A>(addr); NEXT; }
2294
			case 0x88: { II ii = res_N_xix_R<1,B>(addr); NEXT; }
2295
			case 0x89: { II ii = res_N_xix_R<1,C>(addr); NEXT; }
2296
			case 0x8a: { II ii = res_N_xix_R<1,D>(addr); NEXT; }
2297
			case 0x8b: { II ii = res_N_xix_R<1,E>(addr); NEXT; }
2298
			case 0x8c: { II ii = res_N_xix_R<1,H>(addr); NEXT; }
2299
			case 0x8d: { II ii = res_N_xix_R<1,L>(addr); NEXT; }
2300
			case 0x8f: { II ii = res_N_xix_R<1,A>(addr); NEXT; }
2301
			case 0x90: { II ii = res_N_xix_R<2,B>(addr); NEXT; }
2302
			case 0x91: { II ii = res_N_xix_R<2,C>(addr); NEXT; }
2303
			case 0x92: { II ii = res_N_xix_R<2,D>(addr); NEXT; }
2304
			case 0x93: { II ii = res_N_xix_R<2,E>(addr); NEXT; }
2305
			case 0x94: { II ii = res_N_xix_R<2,H>(addr); NEXT; }
2306
			case 0x95: { II ii = res_N_xix_R<2,L>(addr); NEXT; }
2307
			case 0x97: { II ii = res_N_xix_R<2,A>(addr); NEXT; }
2308
			case 0x98: { II ii = res_N_xix_R<3,B>(addr); NEXT; }
2309
			case 0x99: { II ii = res_N_xix_R<3,C>(addr); NEXT; }
2310
			case 0x9a: { II ii = res_N_xix_R<3,D>(addr); NEXT; }
2311
			case 0x9b: { II ii = res_N_xix_R<3,E>(addr); NEXT; }
2312
			case 0x9c: { II ii = res_N_xix_R<3,H>(addr); NEXT; }
2313
			case 0x9d: { II ii = res_N_xix_R<3,L>(addr); NEXT; }
2314
			case 0x9f: { II ii = res_N_xix_R<3,A>(addr); NEXT; }
2315
			case 0xa0: { II ii = res_N_xix_R<4,B>(addr); NEXT; }
2316
			case 0xa1: { II ii = res_N_xix_R<4,C>(addr); NEXT; }
2317
			case 0xa2: { II ii = res_N_xix_R<4,D>(addr); NEXT; }
2318
			case 0xa3: { II ii = res_N_xix_R<4,E>(addr); NEXT; }
2319
			case 0xa4: { II ii = res_N_xix_R<4,H>(addr); NEXT; }
2320
			case 0xa5: { II ii = res_N_xix_R<4,L>(addr); NEXT; }
2321
			case 0xa7: { II ii = res_N_xix_R<4,A>(addr); NEXT; }
2322
			case 0xa8: { II ii = res_N_xix_R<5,B>(addr); NEXT; }
2323
			case 0xa9: { II ii = res_N_xix_R<5,C>(addr); NEXT; }
2324
			case 0xaa: { II ii = res_N_xix_R<5,D>(addr); NEXT; }
2325
			case 0xab: { II ii = res_N_xix_R<5,E>(addr); NEXT; }
2326
			case 0xac: { II ii = res_N_xix_R<5,H>(addr); NEXT; }
2327
			case 0xad: { II ii = res_N_xix_R<5,L>(addr); NEXT; }
2328
			case 0xaf: { II ii = res_N_xix_R<5,A>(addr); NEXT; }
2329
			case 0xb0: { II ii = res_N_xix_R<6,B>(addr); NEXT; }
2330
			case 0xb1: { II ii = res_N_xix_R<6,C>(addr); NEXT; }
2331
			case 0xb2: { II ii = res_N_xix_R<6,D>(addr); NEXT; }
2332
			case 0xb3: { II ii = res_N_xix_R<6,E>(addr); NEXT; }
2333
			case 0xb4: { II ii = res_N_xix_R<6,H>(addr); NEXT; }
2334
			case 0xb5: { II ii = res_N_xix_R<6,L>(addr); NEXT; }
2335
			case 0xb7: { II ii = res_N_xix_R<6,A>(addr); NEXT; }
2336
			case 0xb8: { II ii = res_N_xix_R<7,B>(addr); NEXT; }
2337
			case 0xb9: { II ii = res_N_xix_R<7,C>(addr); NEXT; }
2338
			case 0xba: { II ii = res_N_xix_R<7,D>(addr); NEXT; }
2339
			case 0xbb: { II ii = res_N_xix_R<7,E>(addr); NEXT; }
2340
			case 0xbc: { II ii = res_N_xix_R<7,H>(addr); NEXT; }
2341
			case 0xbd: { II ii = res_N_xix_R<7,L>(addr); NEXT; }
2342
			case 0xbf: { II ii = res_N_xix_R<7,A>(addr); NEXT; }
2343
			case 0x86: { II ii = res_N_xix_R<0,DUMMY>(addr); NEXT; }
2344
			case 0x8e: { II ii = res_N_xix_R<1,DUMMY>(addr); NEXT; }
2345
			case 0x96: { II ii = res_N_xix_R<2,DUMMY>(addr); NEXT; }
2346
			case 0x9e: { II ii = res_N_xix_R<3,DUMMY>(addr); NEXT; }
2347
			case 0xa6: { II ii = res_N_xix_R<4,DUMMY>(addr); NEXT; }
2348
			case 0xae: { II ii = res_N_xix_R<5,DUMMY>(addr); NEXT; }
2349
			case 0xb6: { II ii = res_N_xix_R<6,DUMMY>(addr); NEXT; }
2350
			case 0xbe: { II ii = res_N_xix_R<7,DUMMY>(addr); NEXT; }
2351
2352
			case 0xc0: { II ii = set_N_xix_R<0,B>(addr); NEXT; }
2353
			case 0xc1: { II ii = set_N_xix_R<0,C>(addr); NEXT; }
2354
			case 0xc2: { II ii = set_N_xix_R<0,D>(addr); NEXT; }
2355
			case 0xc3: { II ii = set_N_xix_R<0,E>(addr); NEXT; }
2356
			case 0xc4: { II ii = set_N_xix_R<0,H>(addr); NEXT; }
2357
			case 0xc5: { II ii = set_N_xix_R<0,L>(addr); NEXT; }
2358
			case 0xc7: { II ii = set_N_xix_R<0,A>(addr); NEXT; }
2359
			case 0xc8: { II ii = set_N_xix_R<1,B>(addr); NEXT; }
2360
			case 0xc9: { II ii = set_N_xix_R<1,C>(addr); NEXT; }
2361
			case 0xca: { II ii = set_N_xix_R<1,D>(addr); NEXT; }
2362
			case 0xcb: { II ii = set_N_xix_R<1,E>(addr); NEXT; }
2363
			case 0xcc: { II ii = set_N_xix_R<1,H>(addr); NEXT; }
2364
			case 0xcd: { II ii = set_N_xix_R<1,L>(addr); NEXT; }
2365
			case 0xcf: { II ii = set_N_xix_R<1,A>(addr); NEXT; }
2366
			case 0xd0: { II ii = set_N_xix_R<2,B>(addr); NEXT; }
2367
			case 0xd1: { II ii = set_N_xix_R<2,C>(addr); NEXT; }
2368
			case 0xd2: { II ii = set_N_xix_R<2,D>(addr); NEXT; }
2369
			case 0xd3: { II ii = set_N_xix_R<2,E>(addr); NEXT; }
2370
			case 0xd4: { II ii = set_N_xix_R<2,H>(addr); NEXT; }
2371
			case 0xd5: { II ii = set_N_xix_R<2,L>(addr); NEXT; }
2372
			case 0xd7: { II ii = set_N_xix_R<2,A>(addr); NEXT; }
2373
			case 0xd8: { II ii = set_N_xix_R<3,B>(addr); NEXT; }
2374
			case 0xd9: { II ii = set_N_xix_R<3,C>(addr); NEXT; }
2375
			case 0xda: { II ii = set_N_xix_R<3,D>(addr); NEXT; }
2376
			case 0xdb: { II ii = set_N_xix_R<3,E>(addr); NEXT; }
2377
			case 0xdc: { II ii = set_N_xix_R<3,H>(addr); NEXT; }
2378
			case 0xdd: { II ii = set_N_xix_R<3,L>(addr); NEXT; }
2379
			case 0xdf: { II ii = set_N_xix_R<3,A>(addr); NEXT; }
2380
			case 0xe0: { II ii = set_N_xix_R<4,B>(addr); NEXT; }
2381
			case 0xe1: { II ii = set_N_xix_R<4,C>(addr); NEXT; }
2382
			case 0xe2: { II ii = set_N_xix_R<4,D>(addr); NEXT; }
2383
			case 0xe3: { II ii = set_N_xix_R<4,E>(addr); NEXT; }
2384
			case 0xe4: { II ii = set_N_xix_R<4,H>(addr); NEXT; }
2385
			case 0xe5: { II ii = set_N_xix_R<4,L>(addr); NEXT; }
2386
			case 0xe7: { II ii = set_N_xix_R<4,A>(addr); NEXT; }
2387
			case 0xe8: { II ii = set_N_xix_R<5,B>(addr); NEXT; }
2388
			case 0xe9: { II ii = set_N_xix_R<5,C>(addr); NEXT; }
2389
			case 0xea: { II ii = set_N_xix_R<5,D>(addr); NEXT; }
2390
			case 0xeb: { II ii = set_N_xix_R<5,E>(addr); NEXT; }
2391
			case 0xec: { II ii = set_N_xix_R<5,H>(addr); NEXT; }
2392
			case 0xed: { II ii = set_N_xix_R<5,L>(addr); NEXT; }
2393
			case 0xef: { II ii = set_N_xix_R<5,A>(addr); NEXT; }
2394
			case 0xf0: { II ii = set_N_xix_R<6,B>(addr); NEXT; }
2395
			case 0xf1: { II ii = set_N_xix_R<6,C>(addr); NEXT; }
2396
			case 0xf2: { II ii = set_N_xix_R<6,D>(addr); NEXT; }
2397
			case 0xf3: { II ii = set_N_xix_R<6,E>(addr); NEXT; }
2398
			case 0xf4: { II ii = set_N_xix_R<6,H>(addr); NEXT; }
2399
			case 0xf5: { II ii = set_N_xix_R<6,L>(addr); NEXT; }
2400
			case 0xf7: { II ii = set_N_xix_R<6,A>(addr); NEXT; }
2401
			case 0xf8: { II ii = set_N_xix_R<7,B>(addr); NEXT; }
2402
			case 0xf9: { II ii = set_N_xix_R<7,C>(addr); NEXT; }
2403
			case 0xfa: { II ii = set_N_xix_R<7,D>(addr); NEXT; }
2404
			case 0xfb: { II ii = set_N_xix_R<7,E>(addr); NEXT; }
2405
			case 0xfc: { II ii = set_N_xix_R<7,H>(addr); NEXT; }
2406
			case 0xfd: { II ii = set_N_xix_R<7,L>(addr); NEXT; }
2407
			case 0xff: { II ii = set_N_xix_R<7,A>(addr); NEXT; }
2408
			case 0xc6: { II ii = set_N_xix_R<0,DUMMY>(addr); NEXT; }
2409
			case 0xce: { II ii = set_N_xix_R<1,DUMMY>(addr); NEXT; }
2410
			case 0xd6: { II ii = set_N_xix_R<2,DUMMY>(addr); NEXT; }
2411
			case 0xde: { II ii = set_N_xix_R<3,DUMMY>(addr); NEXT; }
2412
			case 0xe6: { II ii = set_N_xix_R<4,DUMMY>(addr); NEXT; }
2413
			case 0xee: { II ii = set_N_xix_R<5,DUMMY>(addr); NEXT; }
2414
			case 0xf6: { II ii = set_N_xix_R<6,DUMMY>(addr); NEXT; }
2415
			case 0xfe: { II ii = set_N_xix_R<7,DUMMY>(addr); NEXT; }
2416
			default: UNREACHABLE;
2417
		}
2418
	}
2419
}
2420
2421
template<typename T> ExecIRQ CPUCore<T>::getExecIRQ() const
2422
{
2423
	if (nmiEdge) [[unlikely]] return ExecIRQ::NMI;
2424
	if (IRQStatus && getIFF1() && !prevWasEI()) [[unlikely]] return ExecIRQ::IRQ;
2425
	return ExecIRQ::NONE;
2426
}
2427
2428
template<typename T> void CPUCore<T>::executeSlow(ExecIRQ execIRQ)
2429
{
2430
	if (execIRQ == ExecIRQ::NMI) [[unlikely]] {
2431
		nmiEdge = false;
2432
		nmi(); // NMI occurred
2433
	} else if (execIRQ == ExecIRQ::IRQ) [[unlikely]] {
2434
		// normal interrupt
2435
		if (prevWasLDAI()) [[unlikely]] {
2436
			// HACK!!!
2437
			// The 'ld a,i' or 'ld a,r' instruction copies the IFF2
2438
			// bit to the V flag. Though when the Z80 accepts an
2439
			// IRQ directly after this instruction, the V flag is 0
2440
			// (instead of the expected value 1). This can probably
2441
			// be explained if you look at the pipeline of the Z80.
2442
			// But for speed reasons we implement it here as a
2443
			// fix-up (a hack) in the IRQ routine. This behaviour
2444
			// is actually a bug in the Z80.
2445
			// Thanks to n_n for reporting this behaviour. I think
2446
			// this was discovered by GuyveR800. Also thanks to
2447
			// n_n for writing a test program that demonstrates
2448
			// this quirk.
2449
			// I also wrote a test program that demonstrates this
2450
			// behaviour is the same whether 'ld a,i' is preceded
2451
			// by a 'ei' instruction or not (so it's not caused by
2452
			// the 'delayed IRQ acceptance of ei').
2453
			assert(getF() & V_FLAG);
2454
			setF(getF() & ~V_FLAG);
2455
		}
2456
		IRQAccept.signal();
2457
		switch (getIM()) {
2458
			case 0: irq0();
2459
				break;
2460
			case 1: irq1();
2461
				break;
2462
			case 2: irq2();
2463
				break;
2464
			default:
2465
				UNREACHABLE;
2466
		}
2467
	} else if (getHALT()) [[unlikely]] {
2468
		// in halt mode
2469
		incR(narrow_cast<uint8_t>(T::advanceHalt(T::HALT_STATES, scheduler.getNext())));
2470
		setSlowInstructions();
2471
	} else {
2472
		assert(T::limitReached()); // we want only one instruction
2473
		executeInstructions();
2474
		endInstruction();
2475
2476
		if constexpr (T::IS_R800) {
2477
			if (/*unlikely*/(prev2WasCall()) && /*likely*/(!prevWasPopRet())) [[unlikely]] {
2478
				// On R800 a CALL or RST instruction not _immediately_
2479
				// followed by a (single-byte) POP or RET instruction
2480
				// causes an extra cycle in that following instruction.
2481
				// No idea why yet. See doc/internal/r800-call.txt
2482
				// for more information.
2483
				//
2484
				// TODO this implementation adds the extra cycle at
2485
				// the end of the instruction POP/RET. It is not known
2486
				// where in the instruction the real R800 adds this cycle.
2487
				T::add(1);
2488
			}
2489
		}
2490
	}
2491
}
2492
2493
template<typename T> void CPUCore<T>::execute(bool fastForward)
2494
{
2495
	// In fast-forward mode, breakpoints, watchpoints or debug conditions
2496
	// won't trigger. It is possible we already are in break mode, but
2497
	// break is ignored in fast-forward mode.
2498
	assert(fastForward || !interface->isBreaked());
2499
	if (fastForward) {
2500
		interface->setFastForward(true);
2501
	}
2502
	execute2(fastForward);
2503
	interface->setFastForward(false);
2504
}
2505
2506
template<typename T> void CPUCore<T>::execute2(bool fastForward)
2507
{
2508
	// note: Don't use getTimeFast() here, because 'once in a while' we
2509
	//       need to CPUClock::sync() to avoid overflow.
2510
	//       Should be done at least once per second (approx). So only
2511
	//       once in this method is enough.
2512
	scheduler.schedule(T::getTime());
2513
	setSlowInstructions();
2514
2515
	// Note: we call scheduler _after_ executing the instruction and before
2516
	// deciding between executeFast() and executeSlow() (because a
2517
	// SyncPoint could set an IRQ and then we must choose executeSlow())
2518
	if (fastForward || !interface->anyBreakPoints()) {
2519
		// fast path, no breakpoints, no tracing
2520
		do {
2521
			if (slowInstructions) {
2522
				--slowInstructions;
2523
				executeSlow(getExecIRQ());
2524
				scheduler.schedule(T::getTimeFast());
2525
			} else {
2526
				while (slowInstructions == 0) {
2527
					T::enableLimit(); // does CPUClock::sync()
2528
					if (!T::limitReached()) [[likely]] {
2529
						// multiple instructions
2530
						executeInstructions();
2531
						// note: pipeline only shifted one
2532
						// step for multiple instructions
2533
						endInstruction();
2534
					}
2535
					scheduler.schedule(T::getTimeFast());
2536
					if (needExitCPULoop()) return;
2537
				}
2538
			}
2539
		} while (!needExitCPULoop());
2540
	} else {
2541
		do {
2542
			if (slowInstructions == 0) {
2543
				assert(T::limitReached()); // only one instruction
2544
				executeInstructions();
2545
				endInstruction();
2546
			} else {
2547
				--slowInstructions;
2548
				executeSlow(getExecIRQ());
2549
			}
2550
			// Don't use getTimeFast() here, we need a call to
2551
			// CPUClock::sync() 'once in a while'. (During a
2552
			// reverse fast-forward this wasn't always the case).
2553
			scheduler.schedule(T::getTime());
2554
2555
			// Only check for breakpoints when we're not about to jump to an IRQ handler.
2556
			//
2557
			// This fixes the following problem reported by Grauw:
2558
			//
2559
			//   I found a breakpoints bug: sometimes a breakpoint gets hit twice even
2560
			//   though the code is executed once. This manifests itself in my profiler
2561
			//   as an imbalance between section begin- and end-calls.
2562
			//
2563
			//   Turns out this occurs when an interrupt occurs exactly on the line of
2564
			//   the breakpoint, then the breakpoint gets hit before immediately going
2565
			//   to the ISR, as well as when returning from the ISR.
2566
			//
2567
			//   The IRQ is handled by the Z80 at the end of an instruction. So it
2568
			//   should change the PC before the next instruction is fetched and the
2569
			//   breakpoints should be evaluated during instruction fetch.
2570
			//
2571
			// I think Grauw's analysis is correct. Though for performance reasons we
2572
			// don't emulate the Z80 like that: we don't check for IRQs at the end of
2573
			// every instruction. In the openMSX emulation model, we can only enter an
2574
			// ISR:
2575
			//  - (One instruction after) switching from DI to EI mode.
2576
			//  - After emulating device code. This can be:
2577
			//    * When the Z80 communicated with the device (IO or memory mapped IO).
2578
			//    * The device had set a synchronization point.
2579
			//  In all cases disableLimit() gets called which will cause
2580
			//  limitReached() to return true (and possibly slowInstructions to be > 0).
2581
			// So after most emulated Z80 instructions there can't be a pending IRQ, so
2582
			// checking for it is wasteful. Also synchronization points are handled
2583
			// between emulated Z80 instructions, that means me must check for pending
2584
			// IRQs at the start (instead of end) of an instruction.
2585
			//
2586
			auto execIRQ = getExecIRQ();
2587
			if ((execIRQ == ExecIRQ::NONE) &&
2588
			    interface->checkBreakPoints(getPC())) {
2589
				assert(interface->isBreaked());
2590
				break;
2591
			}
2592
		} while (!needExitCPULoop());
2593
	}
2594
}
2595
2596
template<typename T> template<Reg8 R8> ALWAYS_INLINE uint8_t CPUCore<T>::get8() const {
2597
	if      constexpr (R8 == A)     { return getA(); }
2598
	else if constexpr (R8 == F)     { return getF(); }
2599
	else if constexpr (R8 == B)     { return getB(); }
2600
	else if constexpr (R8 == C)     { return getC(); }
2601
	else if constexpr (R8 == D)     { return getD(); }
2602
	else if constexpr (R8 == E)     { return getE(); }
2603
	else if constexpr (R8 == H)     { return getH(); }
2604
	else if constexpr (R8 == L)     { return getL(); }
2605
	else if constexpr (R8 == IXH)   { return getIXh(); }
2606
	else if constexpr (R8 == IXL)   { return getIXl(); }
2607
	else if constexpr (R8 == IYH)   { return getIYh(); }
2608
	else if constexpr (R8 == IYL)   { return getIYl(); }
2609
	else if constexpr (R8 == REG_I) { return getI(); }
2610
	else if constexpr (R8 == REG_R) { return getR(); }
2611
	else if constexpr (R8 == DUMMY) { return 0; }
2612
	else { UNREACHABLE; }
2613
}
2614
template<typename T> template<Reg16 R16> ALWAYS_INLINE uint16_t CPUCore<T>::get16() const {
2615
	if      constexpr (R16 == AF) { return getAF(); }
2616
	else if constexpr (R16 == BC) { return getBC(); }
2617
	else if constexpr (R16 == DE) { return getDE(); }
2618
	else if constexpr (R16 == HL) { return getHL(); }
2619
	else if constexpr (R16 == IX) { return getIX(); }
2620
	else if constexpr (R16 == IY) { return getIY(); }
2621
	else if constexpr (R16 == SP) { return getSP(); }
2622
	else { UNREACHABLE; }
2623
}
2624
template<typename T> template<Reg8 R8> ALWAYS_INLINE void CPUCore<T>::set8(uint8_t x) {
2625
	if      constexpr (R8 == A)     { setA(x); }
2626
	else if constexpr (R8 == F)     { setF(x); }
2627
	else if constexpr (R8 == B)     { setB(x); }
2628
	else if constexpr (R8 == C)     { setC(x); }
2629
	else if constexpr (R8 == D)     { setD(x); }
2630
	else if constexpr (R8 == E)     { setE(x); }
2631
	else if constexpr (R8 == H)     { setH(x); }
2632
	else if constexpr (R8 == L)     { setL(x); }
2633
	else if constexpr (R8 == IXH)   { setIXh(x); }
2634
	else if constexpr (R8 == IXL)   { setIXl(x); }
2635
	else if constexpr (R8 == IYH)   { setIYh(x); }
2636
	else if constexpr (R8 == IYL)   { setIYl(x); }
2637
	else if constexpr (R8 == REG_I) { setI(x); }
2638
	else if constexpr (R8 == REG_R) { setR(x); }
2639
	else if constexpr (R8 == DUMMY) { /* nothing */ }
2640
	else { UNREACHABLE; }
2641
}
2642
template<typename T> template<Reg16 R16> ALWAYS_INLINE void CPUCore<T>::set16(uint16_t x) {
2643
	if      constexpr (R16 == AF) { setAF(x); }
2644
	else if constexpr (R16 == BC) { setBC(x); }
2645
	else if constexpr (R16 == DE) { setDE(x); }
2646
	else if constexpr (R16 == HL) { setHL(x); }
2647
	else if constexpr (R16 == IX) { setIX(x); }
2648
	else if constexpr (R16 == IY) { setIY(x); }
2649
	else if constexpr (R16 == SP) { setSP(x); }
2650
	else { UNREACHABLE; }
2651
}
2652
2653
// LD r,r
2654
template<typename T> template<Reg8 DST, Reg8 SRC, int EE> II CPUCore<T>::ld_R_R() {
2655
	set8<DST>(get8<SRC>()); return {1, T::CC_LD_R_R + EE};
2656
}
2657
2658
// LD SP,ss
2659
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::ld_sp_SS() {
2660
	setSP(get16<REG>()); return {1, T::CC_LD_SP_HL + EE};
2661
}
2662
2663
// LD (ss),a
2664
template<typename T> template<Reg16 REG> II CPUCore<T>::ld_SS_a() {
2665
	T::setMemPtr((getA() << 8) | ((get16<REG>() + 1) & 0xFF));
2666
	WRMEM(get16<REG>(), getA(), T::CC_LD_SS_A_1);
2667
	return {1, T::CC_LD_SS_A};
2668
}
2669
2670
// LD (HL),r
2671
template<typename T> template<Reg8 SRC> II CPUCore<T>::ld_xhl_R() {
2672
	WRMEM(getHL(), get8<SRC>(), T::CC_LD_HL_R_1);
2673
	return {1, T::CC_LD_HL_R};
2674
}
2675
2676
// LD (IXY+e),r
2677
template<typename T> template<Reg16 IXY, Reg8 SRC> II CPUCore<T>::ld_xix_R() {
2678
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_LD_XIX_R_1);
2679
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
2680
	T::setMemPtr(addr);
2681
	WRMEM(addr, get8<SRC>(), T::CC_DD + T::CC_LD_XIX_R_2);
2682
	return {2, T::CC_DD + T::CC_LD_XIX_R};
2683
}
2684
2685
// LD (HL),n
2686
template<typename T> II CPUCore<T>::ld_xhl_byte() {
2687
	uint8_t val = RDMEM_OPCODE<1>(T::CC_LD_HL_N_1);
2688
	WRMEM(getHL(), val, T::CC_LD_HL_N_2);
2689
	return {2, T::CC_LD_HL_N};
2690
}
2691
2692
// LD (IXY+e),n
2693
template<typename T> template<Reg16 IXY> II CPUCore<T>::ld_xix_byte() {
2694
	unsigned tmp = RD_WORD_PC<1>(T::CC_DD + T::CC_LD_XIX_N_1);
2695
	auto ofst = narrow_cast<int8_t>(tmp & 0xFF);
2696
	auto val = narrow_cast<uint8_t>(tmp >> 8);
2697
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
2698
	T::setMemPtr(addr);
2699
	WRMEM(addr, val, T::CC_DD + T::CC_LD_XIX_N_2);
2700
	return {3, T::CC_DD + T::CC_LD_XIX_N};
2701
}
2702
2703
// LD (nn),A
2704
template<typename T> II CPUCore<T>::ld_xbyte_a() {
2705
	unsigned x = RD_WORD_PC<1>(T::CC_LD_NN_A_1);
2706
	T::setMemPtr((getA() << 8) | ((x + 1) & 0xFF));
2707
	WRMEM(x, getA(), T::CC_LD_NN_A_2);
2708
	return {3, T::CC_LD_NN_A};
2709
}
2710
2711
// LD (nn),ss
2712
template<typename T> template<int EE> inline II CPUCore<T>::WR_NN_Y(uint16_t reg) {
2713
	unsigned addr = RD_WORD_PC<1>(T::CC_LD_XX_HL_1 + EE);
2714
	T::setMemPtr(addr + 1);
2715
	WR_WORD(addr, reg, T::CC_LD_XX_HL_2 + EE);
2716
	return {3, T::CC_LD_XX_HL + EE};
2717
}
2718
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::ld_xword_SS() {
2719
	return WR_NN_Y<EE      >(get16<REG>());
2720
}
2721
template<typename T> template<Reg16 REG> II CPUCore<T>::ld_xword_SS_ED() {
2722
	return WR_NN_Y<T::EE_ED>(get16<REG>());
2723
}
2724
2725
// LD A,(ss)
2726
template<typename T> template<Reg16 REG> II CPUCore<T>::ld_a_SS() {
2727
	T::setMemPtr(get16<REG>() + 1);
2728
	setA(RDMEM(get16<REG>(), T::CC_LD_A_SS_1));
2729
	return {1, T::CC_LD_A_SS};
2730
}
2731
2732
// LD A,(nn)
2733
template<typename T> II CPUCore<T>::ld_a_xbyte() {
2734
	unsigned addr = RD_WORD_PC<1>(T::CC_LD_A_NN_1);
2735
	T::setMemPtr(addr + 1);
2736
	setA(RDMEM(addr, T::CC_LD_A_NN_2));
2737
	return {3, T::CC_LD_A_NN};
2738
}
2739
2740
// LD r,n
2741
template<typename T> template<Reg8 DST, int EE> II CPUCore<T>::ld_R_byte() {
2742
	set8<DST>(RDMEM_OPCODE<1>(T::CC_LD_R_N_1 + EE)); return {2, T::CC_LD_R_N + EE};
2743
}
2744
2745
// LD r,(hl)
2746
template<typename T> template<Reg8 DST> II CPUCore<T>::ld_R_xhl() {
2747
	set8<DST>(RDMEM(getHL(), T::CC_LD_R_HL_1)); return {1, T::CC_LD_R_HL};
2748
}
2749
2750
// LD r,(IXY+e)
2751
template<typename T> template<Reg8 DST, Reg16 IXY> II CPUCore<T>::ld_R_xix() {
2752
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_LD_R_XIX_1);
2753
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
2754
	T::setMemPtr(addr);
2755
	set8<DST>(RDMEM(addr, T::CC_DD + T::CC_LD_R_XIX_2));
2756
	return {2, T::CC_DD + T::CC_LD_R_XIX};
2757
}
2758
2759
// LD ss,(nn)
2760
template<typename T> template<int EE> inline uint16_t CPUCore<T>::RD_P_XX() {
2761
	unsigned addr = RD_WORD_PC<1>(T::CC_LD_HL_XX_1 + EE);
2762
	T::setMemPtr(addr + 1);
2763
	return RD_WORD(addr, T::CC_LD_HL_XX_2 + EE);
2764
}
2765
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::ld_SS_xword() {
2766
	set16<REG>(RD_P_XX<EE>());       return {3, T::CC_LD_HL_XX + EE};
2767
}
2768
template<typename T> template<Reg16 REG> II CPUCore<T>::ld_SS_xword_ED() {
2769
	set16<REG>(RD_P_XX<T::EE_ED>()); return {3, T::CC_LD_HL_XX + T::EE_ED};
2770
}
2771
2772
// LD ss,nn
2773
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::ld_SS_word() {
2774
	set16<REG>(RD_WORD_PC<1>(T::CC_LD_SS_NN_1 + EE)); return {3, T::CC_LD_SS_NN + EE};
2775
}
2776
2777
2778
// ADC A,r
2779
template<typename T> inline void CPUCore<T>::ADC(uint8_t reg) {
2780
	unsigned res = getA() + reg + ((getF() & C_FLAG) ? 1 : 0);
2781
	uint8_t f = ((res & 0x100) ? C_FLAG : 0) |
2782
	            ((getA() ^ res ^ reg) & H_FLAG) |
2783
	            (((getA() ^ res) & (reg ^ res) & 0x80) >> 5) | // V_FLAG
2784
	            0; // N_FLAG
2785
	if constexpr (T::IS_R800) {
2786
		f |= table.ZS[res & 0xFF];
2787
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
2788
	} else {
2789
		f |= table.ZSXY[res & 0xFF];
2790
	}
2791
	setF(f);
2792
	setA(narrow_cast<uint8_t>(res));
2793
}
2794
template<typename T> inline II CPUCore<T>::adc_a_a() {
2795
	unsigned res = 2 * getA() + ((getF() & C_FLAG) ? 1 : 0);
2796
	uint8_t f = ((res & 0x100) ? C_FLAG : 0) |
2797
	            (res & H_FLAG) |
2798
	            (((getA() ^ res) & 0x80) >> 5) | // V_FLAG
2799
	            0; // N_FLAG
2800
	if constexpr (T::IS_R800) {
2801
		f |= table.ZS[res & 0xFF];
2802
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
2803
	} else {
2804
		f |= table.ZSXY[res & 0xFF];
2805
	}
2806
	setF(f);
2807
	setA(narrow_cast<uint8_t>(res));
2808
	return {1, T::CC_CP_R};
2809
}
2810
template<typename T> template<Reg8 SRC, int EE> II CPUCore<T>::adc_a_R() {
2811
	ADC(get8<SRC>()); return {1, T::CC_CP_R + EE};
2812
}
2813
template<typename T> II CPUCore<T>::adc_a_byte() {
2814
	ADC(RDMEM_OPCODE<1>(T::CC_CP_N_1)); return {2, T::CC_CP_N};
2815
}
2816
template<typename T> II CPUCore<T>::adc_a_xhl() {
2817
	ADC(RDMEM(getHL(), T::CC_CP_XHL_1)); return {1, T::CC_CP_XHL};
2818
}
2819
template<typename T> template<Reg16 IXY> II CPUCore<T>::adc_a_xix() {
2820
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_CP_XIX_1);
2821
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
2822
	T::setMemPtr(addr);
2823
	ADC(RDMEM(addr, T::CC_DD + T::CC_CP_XIX_2));
2824
	return {2, T::CC_DD + T::CC_CP_XIX};
2825
}
2826
2827
// ADD A,r
2828
template<typename T> inline void CPUCore<T>::ADD(uint8_t reg) {
2829
	unsigned res = getA() + reg;
2830
	uint8_t f = ((res & 0x100) ? C_FLAG : 0) |
2831
	            ((getA() ^ res ^ reg) & H_FLAG) |
2832
	            (((getA() ^ res) & (reg ^ res) & 0x80) >> 5) | // V_FLAG
2833
	            0; // N_FLAG
2834
	if constexpr (T::IS_R800) {
2835
		f |= table.ZS[res & 0xFF];
2836
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
2837
	} else {
2838
		f |= table.ZSXY[res & 0xFF];
2839
	}
2840
	setF(f);
2841
	setA(narrow_cast<uint8_t>(res));
2842
}
2843
template<typename T> inline II CPUCore<T>::add_a_a() {
2844
	unsigned res = 2 * getA();
2845
	uint8_t f = ((res & 0x100) ? C_FLAG : 0) |
2846
	            (res & H_FLAG) |
2847
	            (((getA() ^ res) & 0x80) >> 5) | // V_FLAG
2848
	            0; // N_FLAG
2849
	if constexpr (T::IS_R800) {
2850
		f |= table.ZS[res & 0xFF];
2851
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
2852
	} else {
2853
		f |= table.ZSXY[res & 0xFF];
2854
	}
2855
	setF(f);
2856
	setA(narrow_cast<uint8_t>(res));
2857
	return {1, T::CC_CP_R};
2858
}
2859
template<typename T> template<Reg8 SRC, int EE> II CPUCore<T>::add_a_R() {
2860
	ADD(get8<SRC>()); return {1, T::CC_CP_R + EE};
2861
}
2862
template<typename T> II CPUCore<T>::add_a_byte() {
2863
	ADD(RDMEM_OPCODE<1>(T::CC_CP_N_1)); return {2, T::CC_CP_N};
2864
}
2865
template<typename T> II CPUCore<T>::add_a_xhl() {
2866
	ADD(RDMEM(getHL(), T::CC_CP_XHL_1)); return {1, T::CC_CP_XHL};
2867
}
2868
template<typename T> template<Reg16 IXY> II CPUCore<T>::add_a_xix() {
2869
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_CP_XIX_1);
2870
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
2871
	T::setMemPtr(addr);
2872
	ADD(RDMEM(addr, T::CC_DD + T::CC_CP_XIX_2));
2873
	return {2, T::CC_DD + T::CC_CP_XIX};
2874
}
2875
2876
// AND r
2877
template<typename T> inline void CPUCore<T>::AND(uint8_t reg) {
2878
	setA(getA() & reg);
2879
	uint8_t f = 0;
2880
	if constexpr (T::IS_R800) {
2881
		f |= table.ZSPH[getA()];
2882
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
2883
	} else {
2884
		f |= table.ZSPXY[getA()];
2885
		f |= H_FLAG;
2886
	}
2887
	setF(f);
2888
}
2889
template<typename T> II CPUCore<T>::and_a() {
2890
	uint8_t f = 0;
2891
	if constexpr (T::IS_R800) {
2892
		f |= table.ZSPH[getA()];
2893
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
2894
	} else {
2895
		f |= table.ZSPXY[getA()];
2896
		f |= H_FLAG;
2897
	}
2898
	setF(f);
2899
	return {1, T::CC_CP_R};
2900
}
2901
template<typename T> template<Reg8 SRC, int EE> II CPUCore<T>::and_R() {
2902
	AND(get8<SRC>()); return {1, T::CC_CP_R + EE};
2903
}
2904
template<typename T> II CPUCore<T>::and_byte() {
2905
	AND(RDMEM_OPCODE<1>(T::CC_CP_N_1)); return {2, T::CC_CP_N};
2906
}
2907
template<typename T> II CPUCore<T>::and_xhl() {
2908
	AND(RDMEM(getHL(), T::CC_CP_XHL_1)); return {1, T::CC_CP_XHL};
2909
}
2910
template<typename T> template<Reg16 IXY> II CPUCore<T>::and_xix() {
2911
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_CP_XIX_1);
2912
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
2913
	T::setMemPtr(addr);
2914
	AND(RDMEM(addr, T::CC_DD + T::CC_CP_XIX_2));
2915
	return {2, T::CC_DD + T::CC_CP_XIX};
2916
}
2917
2918
// CP r
2919
template<typename T> inline void CPUCore<T>::CP(uint8_t reg) {
2920
	unsigned q = getA() - reg;
2921
	uint8_t f = table.ZS[q & 0xFF] |
2922
	            ((q & 0x100) ? C_FLAG : 0) |
2923
	            N_FLAG |
2924
	            ((getA() ^ uint8_t(q) ^ reg) & H_FLAG) |
2925
	            (((reg ^ getA()) & (getA() ^ uint8_t(q)) & 0x80) >> 5); // V_FLAG
2926
	if constexpr (T::IS_R800) {
2927
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
2928
	} else {
2929
		f |= uint8_t(reg & (X_FLAG | Y_FLAG)); // XY from operand, not from result
2930
	}
2931
	setF(f);
2932
}
2933
template<typename T> II CPUCore<T>::cp_a() {
2934
	uint8_t f = ZS0 | N_FLAG;
2935
	if constexpr (T::IS_R800) {
2936
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
2937
	} else {
2938
		f |= uint8_t(getA() & (X_FLAG | Y_FLAG)); // XY from operand, not from result
2939
	}
2940
	setF(f);
2941
	return {1, T::CC_CP_R};
2942
}
2943
template<typename T> template<Reg8 SRC, int EE> II CPUCore<T>::cp_R() {
2944
	CP(get8<SRC>()); return {1, T::CC_CP_R + EE};
2945
}
2946
template<typename T> II CPUCore<T>::cp_byte() {
2947
	CP(RDMEM_OPCODE<1>(T::CC_CP_N_1)); return {2, T::CC_CP_N};
2948
}
2949
template<typename T> II CPUCore<T>::cp_xhl() {
2950
	CP(RDMEM(getHL(), T::CC_CP_XHL_1)); return {1, T::CC_CP_XHL};
2951
}
2952
template<typename T> template<Reg16 IXY> II CPUCore<T>::cp_xix() {
2953
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_CP_XIX_1);
2954
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
2955
	T::setMemPtr(addr);
2956
	CP(RDMEM(addr, T::CC_DD + T::CC_CP_XIX_2));
2957
	return {2, T::CC_DD + T::CC_CP_XIX};
2958
}
2959
2960
// OR r
2961
template<typename T> inline void CPUCore<T>::OR(uint8_t reg) {
2962
	setA(getA() | reg);
2963
	uint8_t f = 0;
2964
	if constexpr (T::IS_R800) {
2965
		f |= table.ZSP[getA()];
2966
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
2967
	} else {
2968
		f |= table.ZSPXY[getA()];
2969
	}
2970
	setF(f);
2971
}
2972
template<typename T> II CPUCore<T>::or_a() {
2973
	uint8_t f = 0;
2974
	if constexpr (T::IS_R800) {
2975
		f |= table.ZSP[getA()];
2976
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
2977
	} else {
2978
		f |= table.ZSPXY[getA()];
2979
	}
2980
	setF(f);
2981
	return {1, T::CC_CP_R};
2982
}
2983
template<typename T> template<Reg8 SRC, int EE> II CPUCore<T>::or_R() {
2984
	OR(get8<SRC>()); return {1, T::CC_CP_R + EE};
2985
}
2986
template<typename T> II CPUCore<T>::or_byte() {
2987
	OR(RDMEM_OPCODE<1>(T::CC_CP_N_1)); return {2, T::CC_CP_N};
2988
}
2989
template<typename T> II CPUCore<T>::or_xhl() {
2990
	OR(RDMEM(getHL(), T::CC_CP_XHL_1)); return {1, T::CC_CP_XHL};
2991
}
2992
template<typename T> template<Reg16 IXY> II CPUCore<T>::or_xix() {
2993
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_CP_XIX_1);
2994
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
2995
	T::setMemPtr(addr);
2996
	OR(RDMEM(addr, T::CC_DD + T::CC_CP_XIX_2));
2997
	return {2, T::CC_DD + T::CC_CP_XIX};
2998
}
2999
3000
// SBC A,r
3001
template<typename T> inline void CPUCore<T>::SBC(uint8_t reg) {
3002
	unsigned res = getA() - reg - ((getF() & C_FLAG) ? 1 : 0);
3003
	uint8_t f = ((res & 0x100) ? C_FLAG : 0) |
3004
	            N_FLAG |
3005
	            ((getA() ^ res ^ reg) & H_FLAG) |
3006
	            (((reg ^ getA()) & (getA() ^ res) & 0x80) >> 5); // V_FLAG
3007
	if constexpr (T::IS_R800) {
3008
		f |= table.ZS[res & 0xFF];
3009
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3010
	} else {
3011
		f |= table.ZSXY[res & 0xFF];
3012
	}
3013
	setF(f);
3014
	setA(narrow_cast<uint8_t>(res));
3015
}
3016
template<typename T> II CPUCore<T>::sbc_a_a() {
3017
	if constexpr (T::IS_R800) {
3018
		uint16_t t = (getF() & C_FLAG)
3019
		           ? (255 * 256 | ZS255 | C_FLAG | H_FLAG | N_FLAG)
3020
		           : (  0 * 256 | ZS0   |                   N_FLAG);
3021
		setAF(t | (getF() & (X_FLAG | Y_FLAG)));
3022
	} else {
3023
		setAF((getF() & C_FLAG) ?
3024
			(255 * 256 | ZSXY255 | C_FLAG | H_FLAG | N_FLAG) :
3025
			(  0 * 256 | ZSXY0   |                   N_FLAG));
3026
	}
3027
	return {1, T::CC_CP_R};
3028
}
3029
template<typename T> template<Reg8 SRC, int EE> II CPUCore<T>::sbc_a_R() {
3030
	SBC(get8<SRC>()); return {1, T::CC_CP_R + EE};
3031
}
3032
template<typename T> II CPUCore<T>::sbc_a_byte() {
3033
	SBC(RDMEM_OPCODE<1>(T::CC_CP_N_1)); return {2, T::CC_CP_N};
3034
}
3035
template<typename T> II CPUCore<T>::sbc_a_xhl() {
3036
	SBC(RDMEM(getHL(), T::CC_CP_XHL_1)); return {1, T::CC_CP_XHL};
3037
}
3038
template<typename T> template<Reg16 IXY> II CPUCore<T>::sbc_a_xix() {
3039
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_CP_XIX_1);
3040
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
3041
	T::setMemPtr(addr);
3042
	SBC(RDMEM(addr, T::CC_DD + T::CC_CP_XIX_2));
3043
	return {2, T::CC_DD + T::CC_CP_XIX};
3044
}
3045
3046
// SUB r
3047
template<typename T> inline void CPUCore<T>::SUB(uint8_t reg) {
3048
	unsigned res = getA() - reg;
3049
	uint8_t f = ((res & 0x100) ? C_FLAG : 0) |
3050
	            N_FLAG |
3051
	            ((getA() ^ res ^ reg) & H_FLAG) |
3052
	            (((reg ^ getA()) & (getA() ^ res) & 0x80) >> 5); // V_FLAG
3053
	if constexpr (T::IS_R800) {
3054
		f |= table.ZS[res & 0xFF];
3055
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3056
	} else {
3057
		f |= table.ZSXY[res & 0xFF];
3058
	}
3059
	setF(f);
3060
	setA(narrow_cast<uint8_t>(res));
3061
}
3062
template<typename T> II CPUCore<T>::sub_a() {
3063
	if constexpr (T::IS_R800) {
3064
		uint16_t t = 0 * 256 | ZS0 | N_FLAG;
3065
		setAF(t | (getF() & (X_FLAG | Y_FLAG)));
3066
	} else {
3067
		setAF(0 * 256 | ZSXY0 | N_FLAG);
3068
	}
3069
	return {1, T::CC_CP_R};
3070
}
3071
template<typename T> template<Reg8 SRC, int EE> II CPUCore<T>::sub_R() {
3072
	SUB(get8<SRC>()); return {1, T::CC_CP_R + EE};
3073
}
3074
template<typename T> II CPUCore<T>::sub_byte() {
3075
	SUB(RDMEM_OPCODE<1>(T::CC_CP_N_1)); return {2, T::CC_CP_N};
3076
}
3077
template<typename T> II CPUCore<T>::sub_xhl() {
3078
	SUB(RDMEM(getHL(), T::CC_CP_XHL_1)); return {1, T::CC_CP_XHL};
3079
}
3080
template<typename T> template<Reg16 IXY> II CPUCore<T>::sub_xix() {
3081
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_CP_XIX_1);
3082
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
3083
	T::setMemPtr(addr);
3084
	SUB(RDMEM(addr, T::CC_DD + T::CC_CP_XIX_2));
3085
	return {2, T::CC_DD + T::CC_CP_XIX};
3086
}
3087
3088
// XOR r
3089
template<typename T> inline void CPUCore<T>::XOR(uint8_t reg) {
3090
	setA(getA() ^ reg);
3091
	uint8_t f = 0;
3092
	if constexpr (T::IS_R800) {
3093
		f |= table.ZSP[getA()];
3094
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3095
	} else {
3096
		f |= table.ZSPXY[getA()];
3097
	}
3098
	setF(f);
3099
}
3100
template<typename T> II CPUCore<T>::xor_a() {
3101
	if constexpr (T::IS_R800) {
3102
		uint16_t t = 0 * 256 + ZSP0;
3103
		setAF(t | (getF() & (X_FLAG | Y_FLAG)));
3104
	} else {
3105
		setAF(0 * 256 + ZSPXY0);
3106
	}
3107
	return {1, T::CC_CP_R};
3108
}
3109
template<typename T> template<Reg8 SRC, int EE> II CPUCore<T>::xor_R() {
3110
	XOR(get8<SRC>()); return {1, T::CC_CP_R + EE};
3111
}
3112
template<typename T> II CPUCore<T>::xor_byte() {
3113
	XOR(RDMEM_OPCODE<1>(T::CC_CP_N_1)); return {2, T::CC_CP_N};
3114
}
3115
template<typename T> II CPUCore<T>::xor_xhl() {
3116
	XOR(RDMEM(getHL(), T::CC_CP_XHL_1)); return {1, T::CC_CP_XHL};
3117
}
3118
template<typename T> template<Reg16 IXY> II CPUCore<T>::xor_xix() {
3119
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_CP_XIX_1);
3120
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
3121
	T::setMemPtr(addr);
3122
	XOR(RDMEM(addr, T::CC_DD + T::CC_CP_XIX_2));
3123
	return {2, T::CC_DD + T::CC_CP_XIX};
3124
}
3125
3126
3127
// DEC r
3128
template<typename T> inline uint8_t CPUCore<T>::DEC(uint8_t reg) {
3129
	uint8_t res = reg - 1;
3130
	uint8_t f = ((reg & ~res & 0x80) >> 5) | // V_FLAG
3131
	            (((res & 0x0F) + 1) & H_FLAG) |
3132
	            N_FLAG;
3133
	if constexpr (T::IS_R800) {
3134
		f |= uint8_t(getF() & (C_FLAG | X_FLAG | Y_FLAG));
3135
		f |= table.ZS[res];
3136
	} else {
3137
		f |= uint8_t(getF() & C_FLAG);
3138
		f |= table.ZSXY[res];
3139
	}
3140
	setF(f);
3141
	return res;
3142
}
3143
template<typename T> template<Reg8 REG, int EE> II CPUCore<T>::dec_R() {
3144
	set8<REG>(DEC(get8<REG>())); return {1, T::CC_INC_R + EE};
3145
}
3146
template<typename T> template<int EE> inline void CPUCore<T>::DEC_X(unsigned x) {
3147
	uint8_t val = DEC(RDMEM(x, T::CC_INC_XHL_1 + EE));
3148
	WRMEM(x, val, T::CC_INC_XHL_2 + EE);
3149
}
3150
template<typename T> II CPUCore<T>::dec_xhl() {
3151
	DEC_X<0>(getHL());
3152
	return {1, T::CC_INC_XHL};
3153
}
3154
template<typename T> template<Reg16 IXY> II CPUCore<T>::dec_xix() {
3155
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_INC_XIX_1);
3156
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
3157
	T::setMemPtr(addr);
3158
	DEC_X<T::CC_DD + T::EE_INC_XIX>(addr);
3159
	return {2, T::CC_INC_XHL + T::CC_DD + T::EE_INC_XIX};
3160
}
3161
3162
// INC r
3163
template<typename T> inline uint8_t CPUCore<T>::INC(uint8_t reg) {
3164
	reg++;
3165
	uint8_t f = ((reg & -reg & 0x80) >> 5) | // V_FLAG
3166
	            (((reg & 0x0F) - 1) & H_FLAG) |
3167
	            0; // N_FLAG
3168
	if constexpr (T::IS_R800) {
3169
		f |= uint8_t(getF() & (C_FLAG | X_FLAG | Y_FLAG));
3170
		f |= table.ZS[reg];
3171
	} else {
3172
		f |= uint8_t(getF() & C_FLAG);
3173
		f |= table.ZSXY[reg];
3174
	}
3175
	setF(f);
3176
	return reg;
3177
}
3178
template<typename T> template<Reg8 REG, int EE> II CPUCore<T>::inc_R() {
3179
	set8<REG>(INC(get8<REG>())); return {1, T::CC_INC_R + EE};
3180
}
3181
template<typename T> template<int EE> inline void CPUCore<T>::INC_X(unsigned x) {
3182
	uint8_t val = INC(RDMEM(x, T::CC_INC_XHL_1 + EE));
3183
	WRMEM(x, val, T::CC_INC_XHL_2 + EE);
3184
}
3185
template<typename T> II CPUCore<T>::inc_xhl() {
3186
	INC_X<0>(getHL());
3187
	return {1, T::CC_INC_XHL};
3188
}
3189
template<typename T> template<Reg16 IXY> II CPUCore<T>::inc_xix() {
3190
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_DD + T::CC_INC_XIX_1);
3191
	unsigned addr = narrow_cast<uint16_t>(get16<IXY>() + ofst);
3192
	T::setMemPtr(addr);
3193
	INC_X<T::CC_DD + T::EE_INC_XIX>(addr);
3194
	return {2, T::CC_INC_XHL + T::CC_DD + T::EE_INC_XIX};
3195
}
3196
3197
3198
// ADC HL,ss
3199
template<typename T> template<Reg16 REG> inline II CPUCore<T>::adc_hl_SS() {
3200
	unsigned reg = get16<REG>();
3201
	T::setMemPtr(getHL() + 1);
3202
	unsigned res = getHL() + reg + ((getF() & C_FLAG) ? 1 : 0);
3203
	uint8_t f = uint8_t(res >> 16) | // C_FLAG
3204
	            0; // N_FLAG
3205
	if constexpr (T::IS_R800) {
3206
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3207
	}
3208
	if (res & 0xFFFF) {
3209
		f |= uint8_t(((getHL() ^ res ^ reg) >> 8) & H_FLAG);
3210
		f |= 0; // Z_FLAG
3211
		f |= uint8_t(((getHL() ^ res) & (reg ^ res) & 0x8000) >> 13); // V_FLAG
3212
		if constexpr (T::IS_R800) {
3213
			f |= (res >> 8) & S_FLAG;
3214
		} else {
3215
			f |= (res >> 8) & (S_FLAG | X_FLAG | Y_FLAG);
3216
		}
3217
	} else {
3218
		f |= uint8_t(((getHL() ^ reg) >> 8) & H_FLAG);
3219
		f |= Z_FLAG;
3220
		f |= uint8_t((getHL() & reg & 0x8000) >> 13); // V_FLAG
3221
		f |= 0; // S_FLAG (X_FLAG Y_FLAG)
3222
	}
3223
	setF(f);
3224
	setHL(narrow_cast<uint16_t>(res));
3225
	return {1, T::CC_ADC_HL_SS};
3226
}
3227
template<typename T> II CPUCore<T>::adc_hl_hl() {
3228
	T::setMemPtr(getHL() + 1);
3229
	unsigned res = 2 * getHL() + ((getF() & C_FLAG) ? 1 : 0);
3230
	uint8_t f = uint8_t(res >> 16) | // C_FLAG
3231
	            0; // N_FLAG
3232
	if constexpr (T::IS_R800) {
3233
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3234
	}
3235
	if (res & 0xFFFF) {
3236
		f |= 0; // Z_FLAG
3237
		f |= uint8_t(((getHL() ^ res) & 0x8000) >> 13); // V_FLAG
3238
		if constexpr (T::IS_R800) {
3239
			f |= uint8_t((res >> 8) & (H_FLAG | S_FLAG));
3240
		} else {
3241
			f |= uint8_t((res >> 8) & (H_FLAG | S_FLAG | X_FLAG | Y_FLAG));
3242
		}
3243
	} else {
3244
		f |= Z_FLAG;
3245
		f |= uint8_t((getHL() & 0x8000) >> 13); // V_FLAG
3246
		f |= 0; // H_FLAG S_FLAG (X_FLAG Y_FLAG)
3247
	}
3248
	setF(f);
3249
	setHL(narrow_cast<uint16_t>(res));
3250
	return {1, T::CC_ADC_HL_SS};
3251
}
3252
3253
// ADD HL/IX/IY,ss
3254
template<typename T> template<Reg16 REG1, Reg16 REG2, int EE> II CPUCore<T>::add_SS_TT() {
3255
	unsigned reg1 = get16<REG1>();
3256
	unsigned reg2 = get16<REG2>();
3257
	T::setMemPtr(reg1 + 1);
3258
	unsigned res = reg1 + reg2;
3259
	uint8_t f = uint8_t(((reg1 ^ res ^ reg2) >> 8) & H_FLAG) |
3260
	            uint8_t(res >> 16) | // C_FLAG
3261
	            0; // N_FLAG
3262
	if constexpr (T::IS_R800) {
3263
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | V_FLAG | X_FLAG | Y_FLAG));
3264
	} else {
3265
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | V_FLAG));
3266
		f |= uint8_t((res >> 8) & (X_FLAG | Y_FLAG));
3267
	}
3268
	setF(f);
3269
	set16<REG1>(narrow_cast<uint16_t>(res));
3270
	return {1, T::CC_ADD_HL_SS + EE};
3271
}
3272
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::add_SS_SS() {
3273
	unsigned reg = get16<REG>();
3274
	T::setMemPtr(reg + 1);
3275
	unsigned res = 2 * reg;
3276
	uint8_t f = uint8_t(res >> 16) | // C_FLAG
3277
	            0; // N_FLAG
3278
	if constexpr (T::IS_R800) {
3279
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | V_FLAG | X_FLAG | Y_FLAG));
3280
		f |= uint8_t((res >> 8) & H_FLAG);
3281
	} else {
3282
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | V_FLAG));
3283
		f |= uint8_t((res >> 8) & (H_FLAG | X_FLAG | Y_FLAG));
3284
	}
3285
	setF(f);
3286
	set16<REG>(narrow_cast<uint16_t>(res));
3287
	return {1, T::CC_ADD_HL_SS + EE};
3288
}
3289
3290
// SBC HL,ss
3291
template<typename T> template<Reg16 REG> inline II CPUCore<T>::sbc_hl_SS() {
3292
	unsigned reg = get16<REG>();
3293
	T::setMemPtr(getHL() + 1);
3294
	unsigned res = getHL() - reg - ((getF() & C_FLAG) ? 1 : 0);
3295
	uint8_t f = ((res & 0x10000) ? C_FLAG : 0) |
3296
	            N_FLAG;
3297
	if constexpr (T::IS_R800) {
3298
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3299
	}
3300
	if (res & 0xFFFF) {
3301
		f |= uint8_t(((getHL() ^ res ^ reg) >> 8) & H_FLAG);
3302
		f |= 0; // Z_FLAG
3303
		f |= uint8_t(((reg ^ getHL()) & (getHL() ^ res) & 0x8000) >> 13); // V_FLAG
3304
		if constexpr (T::IS_R800) {
3305
			f |= uint8_t((res >> 8) & S_FLAG);
3306
		} else {
3307
			f |= uint8_t((res >> 8) & (S_FLAG | X_FLAG | Y_FLAG));
3308
		}
3309
	} else {
3310
		f |= uint8_t(((getHL() ^ reg) >> 8) & H_FLAG);
3311
		f |= Z_FLAG;
3312
		f |= uint8_t(((reg ^ getHL()) & getHL() & 0x8000) >> 13); // V_FLAG
3313
		f |= 0; // S_FLAG (X_FLAG Y_FLAG)
3314
	}
3315
	setF(f);
3316
	setHL(narrow_cast<uint16_t>(res));
3317
	return {1, T::CC_ADC_HL_SS};
3318
}
3319
template<typename T> II CPUCore<T>::sbc_hl_hl() {
3320
	T::setMemPtr(getHL() + 1);
3321
	uint8_t f = T::IS_R800 ? (getF() & (X_FLAG | Y_FLAG)) : 0;
3322
	if (getF() & C_FLAG) {
3323
		f |= C_FLAG | H_FLAG | S_FLAG | N_FLAG;
3324
		if constexpr (!T::IS_R800) {
3325
			f |= X_FLAG | Y_FLAG;
3326
		}
3327
		setHL(0xFFFF);
3328
	} else {
3329
		f |= Z_FLAG | N_FLAG;
3330
		setHL(0);
3331
	}
3332
	setF(f);
3333
	return {1, T::CC_ADC_HL_SS};
3334
}
3335
3336
// DEC ss
3337
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::dec_SS() {
3338
	set16<REG>(narrow_cast<uint16_t>(get16<REG>() - 1)); return {1, T::CC_INC_SS + EE};
3339
}
3340
3341
// INC ss
3342
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::inc_SS() {
3343
	set16<REG>(narrow_cast<uint16_t>(get16<REG>() + 1)); return {1, T::CC_INC_SS + EE};
3344
}
3345
3346
3347
// BIT n,r
3348
template<typename T> template<unsigned N, Reg8 REG> II CPUCore<T>::bit_N_R() {
3349
	uint8_t reg = get8<REG>();
3350
	uint8_t f = 0; // N_FLAG
3351
	if constexpr (T::IS_R800) {
3352
		// this is very different from Z80 (not only XY flags)
3353
		f |= uint8_t(getF() & (S_FLAG | V_FLAG | C_FLAG | X_FLAG | Y_FLAG));
3354
		f |= H_FLAG;
3355
		f |= (reg & (1 << N)) ? 0 : Z_FLAG;
3356
	} else {
3357
		f |= table.ZSPH[reg & (1 << N)];
3358
		f |= uint8_t(getF() & C_FLAG);
3359
		f |= uint8_t(reg & (X_FLAG | Y_FLAG));
3360
	}
3361
	setF(f);
3362
	return {1, T::CC_BIT_R};
3363
}
3364
template<typename T> template<unsigned N> inline II CPUCore<T>::bit_N_xhl() {
3365
	uint8_t m = RDMEM(getHL(), T::CC_BIT_XHL_1) & (1 << N);
3366
	uint8_t f = 0; // N_FLAG
3367
	if constexpr (T::IS_R800) {
3368
		f |= uint8_t(getF() & (S_FLAG | V_FLAG | C_FLAG | X_FLAG | Y_FLAG));
3369
		f |= H_FLAG;
3370
		f |= m ? 0 : Z_FLAG;
3371
	} else {
3372
		f |= table.ZSPH[m];
3373
		f |= uint8_t(getF() & C_FLAG);
3374
		f |= uint8_t((T::getMemPtr() >> 8) & (X_FLAG | Y_FLAG));
3375
	}
3376
	setF(f);
3377
	return {1, T::CC_BIT_XHL};
3378
}
3379
template<typename T> template<unsigned N> inline II CPUCore<T>::bit_N_xix(unsigned addr) {
3380
	T::setMemPtr(addr);
3381
	uint8_t m = RDMEM(addr, T::CC_DD + T::CC_BIT_XIX_1) & (1 << N);
3382
	uint8_t f = 0; // N_FLAG
3383
	if constexpr (T::IS_R800) {
3384
		f |= uint8_t(getF() & (S_FLAG | V_FLAG | C_FLAG | X_FLAG | Y_FLAG));
3385
		f |= H_FLAG;
3386
		f |= m ? 0 : Z_FLAG;
3387
	} else {
3388
		f |= table.ZSPH[m];
3389
		f |= uint8_t(getF() & C_FLAG);
3390
		f |= uint8_t((addr >> 8) & (X_FLAG | Y_FLAG));
3391
	}
3392
	setF(f);
3393
	return {3, T::CC_DD + T::CC_BIT_XIX};
3394
}
3395
3396
// RES n,r
3397
static constexpr uint8_t RES(unsigned b, uint8_t reg) {
3398
	return reg & uint8_t(~(1 << b));
3399
}
3400
template<typename T> template<unsigned N, Reg8 REG> II CPUCore<T>::res_N_R() {
3401
	set8<REG>(RES(N, get8<REG>())); return {1, T::CC_SET_R};
3402
}
3403
template<typename T> template<int EE> inline uint8_t CPUCore<T>::RES_X(unsigned bit, unsigned addr) {
3404
	uint8_t res = RES(bit, RDMEM(addr, T::CC_SET_XHL_1 + EE));
3405
	WRMEM(addr, res, T::CC_SET_XHL_2 + EE);
3406
	return res;
3407
}
3408
template<typename T> template<unsigned N> II CPUCore<T>::res_N_xhl() {
3409
	RES_X<0>(N, getHL()); return {1, T::CC_SET_XHL};
3410
}
3411
template<typename T> template<unsigned N, Reg8 REG> II CPUCore<T>::res_N_xix_R(unsigned a) {
3412
	T::setMemPtr(a);
3413
	set8<REG>(RES_X<T::CC_DD + T::EE_SET_XIX>(N, a));
3414
	return {3, T::CC_DD + T::CC_SET_XIX};
3415
}
3416
3417
// SET n,r
3418
static constexpr uint8_t SET(unsigned b, uint8_t reg) {
3419
	return reg | uint8_t(1 << b);
3420
}
3421
template<typename T> template<unsigned N, Reg8 REG> II CPUCore<T>::set_N_R() {
3422
	set8<REG>(SET(N, get8<REG>())); return {1, T::CC_SET_R};
3423
}
3424
template<typename T> template<int EE> inline uint8_t CPUCore<T>::SET_X(unsigned bit, unsigned addr) {
3425
	uint8_t res = SET(bit, RDMEM(addr, T::CC_SET_XHL_1 + EE));
3426
	WRMEM(addr, res, T::CC_SET_XHL_2 + EE);
3427
	return res;
3428
}
3429
template<typename T> template<unsigned N> II CPUCore<T>::set_N_xhl() {
3430
	SET_X<0>(N, getHL()); return {1, T::CC_SET_XHL};
3431
}
3432
template<typename T> template<unsigned N, Reg8 REG> II CPUCore<T>::set_N_xix_R(unsigned a) {
3433
	T::setMemPtr(a);
3434
	set8<REG>(SET_X<T::CC_DD + T::EE_SET_XIX>(N, a));
3435
	return {3, T::CC_DD + T::CC_SET_XIX};
3436
}
3437
3438
// RL r
3439
template<typename T> inline uint8_t CPUCore<T>::RL(uint8_t reg) {
3440
	uint8_t c = reg >> 7;
3441
	reg = narrow_cast<uint8_t>((reg << 1) | ((getF() & C_FLAG) ? 0x01 : 0));
3442
	uint8_t f = c ? C_FLAG : 0;
3443
	if constexpr (T::IS_R800) {
3444
		f |= table.ZSP[reg];
3445
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3446
	} else {
3447
		f |= table.ZSPXY[reg];
3448
	}
3449
	setF(f);
3450
	return reg;
3451
}
3452
template<typename T> template<int EE> inline uint8_t CPUCore<T>::RL_X(unsigned x) {
3453
	uint8_t res = RL(RDMEM(x, T::CC_SET_XHL_1 + EE));
3454
	WRMEM(x, res, T::CC_SET_XHL_2 + EE);
3455
	return res;
3456
}
3457
template<typename T> template<Reg8 REG> II CPUCore<T>::rl_R() {
3458
	set8<REG>(RL(get8<REG>())); return {1, T::CC_SET_R};
3459
}
3460
template<typename T> II CPUCore<T>::rl_xhl() {
3461
	RL_X<0>(getHL()); return {1, T::CC_SET_XHL};
3462
}
3463
template<typename T> template<Reg8 REG> II CPUCore<T>::rl_xix_R(unsigned a) {
3464
	T::setMemPtr(a);
3465
	set8<REG>(RL_X<T::CC_DD + T::EE_SET_XIX>(a));
3466
	return {3, T::CC_DD + T::CC_SET_XIX};
3467
}
3468
3469
// RLC r
3470
template<typename T> inline uint8_t CPUCore<T>::RLC(uint8_t reg) {
3471
	uint8_t c = reg >> 7;
3472
	reg = narrow_cast<uint8_t>((reg << 1) | c);
3473
	uint8_t f = c ? C_FLAG : 0;
3474
	if constexpr (T::IS_R800) {
3475
		f |= table.ZSP[reg];
3476
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3477
	} else {
3478
		f |= table.ZSPXY[reg];
3479
	}
3480
	setF(f);
3481
	return reg;
3482
}
3483
template<typename T> template<int EE> inline uint8_t CPUCore<T>::RLC_X(unsigned x) {
3484
	uint8_t res = RLC(RDMEM(x, T::CC_SET_XHL_1 + EE));
3485
	WRMEM(x, res, T::CC_SET_XHL_2 + EE);
3486
	return res;
3487
}
3488
template<typename T> template<Reg8 REG> II CPUCore<T>::rlc_R() {
3489
	set8<REG>(RLC(get8<REG>())); return {1, T::CC_SET_R};
3490
}
3491
template<typename T> II CPUCore<T>::rlc_xhl() {
3492
	RLC_X<0>(getHL()); return {1, T::CC_SET_XHL};
3493
}
3494
template<typename T> template<Reg8 REG> II CPUCore<T>::rlc_xix_R(unsigned a) {
3495
	T::setMemPtr(a);
3496
	set8<REG>(RLC_X<T::CC_DD + T::EE_SET_XIX>(a));
3497
	return {3, T::CC_DD + T::CC_SET_XIX};
3498
}
3499
3500
// RR r
3501
template<typename T> inline uint8_t CPUCore<T>::RR(uint8_t reg) {
3502
	uint8_t c = reg & 1;
3503
	reg = narrow_cast<uint8_t>((reg >> 1) | ((getF() & C_FLAG) << 7));
3504
	uint8_t f = c ? C_FLAG : 0;
3505
	if constexpr (T::IS_R800) {
3506
		f |= table.ZSP[reg];
3507
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3508
	} else {
3509
		f |= table.ZSPXY[reg];
3510
	}
3511
	setF(f);
3512
	return reg;
3513
}
3514
template<typename T> template<int EE> inline uint8_t CPUCore<T>::RR_X(unsigned x) {
3515
	uint8_t res = RR(RDMEM(x, T::CC_SET_XHL_1 + EE));
3516
	WRMEM(x, res, T::CC_SET_XHL_2 + EE);
3517
	return res;
3518
}
3519
template<typename T> template<Reg8 REG> II CPUCore<T>::rr_R() {
3520
	set8<REG>(RR(get8<REG>())); return {1, T::CC_SET_R};
3521
}
3522
template<typename T> II CPUCore<T>::rr_xhl() {
3523
	RR_X<0>(getHL()); return {1, T::CC_SET_XHL};
3524
}
3525
template<typename T> template<Reg8 REG> II CPUCore<T>::rr_xix_R(unsigned a) {
3526
	T::setMemPtr(a);
3527
	set8<REG>(RR_X<T::CC_DD + T::EE_SET_XIX>(a));
3528
	return {3, T::CC_DD + T::CC_SET_XIX};
3529
}
3530
3531
// RRC r
3532
template<typename T> inline uint8_t CPUCore<T>::RRC(uint8_t reg) {
3533
	uint8_t c = reg & 1;
3534
	reg = narrow_cast<uint8_t>((reg >> 1) | (c << 7));
3535
	uint8_t f = c ? C_FLAG : 0;
3536
	if constexpr (T::IS_R800) {
3537
		f |= table.ZSP[reg];
3538
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3539
	} else {
3540
		f |= table.ZSPXY[reg];
3541
	}
3542
	setF(f);
3543
	return reg;
3544
}
3545
template<typename T> template<int EE> inline uint8_t CPUCore<T>::RRC_X(unsigned x) {
3546
	uint8_t res = RRC(RDMEM(x, T::CC_SET_XHL_1 + EE));
3547
	WRMEM(x, res, T::CC_SET_XHL_2 + EE);
3548
	return res;
3549
}
3550
template<typename T> template<Reg8 REG> II CPUCore<T>::rrc_R() {
3551
	set8<REG>(RRC(get8<REG>())); return {1, T::CC_SET_R};
3552
}
3553
template<typename T> II CPUCore<T>::rrc_xhl() {
3554
	RRC_X<0>(getHL()); return {1, T::CC_SET_XHL};
3555
}
3556
template<typename T> template<Reg8 REG> II CPUCore<T>::rrc_xix_R(unsigned a) {
3557
	T::setMemPtr(a);
3558
	set8<REG>(RRC_X<T::CC_DD + T::EE_SET_XIX>(a));
3559
	return {3, T::CC_DD + T::CC_SET_XIX};
3560
}
3561
3562
// SLA r
3563
template<typename T> inline uint8_t CPUCore<T>::SLA(uint8_t reg) {
3564
	uint8_t c = reg >> 7;
3565
	reg <<= 1;
3566
	uint8_t f = c ? C_FLAG : 0;
3567
	if constexpr (T::IS_R800) {
3568
		f |= table.ZSP[reg];
3569
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3570
	} else {
3571
		f |= table.ZSPXY[reg];
3572
	}
3573
	setF(f);
3574
	return reg;
3575
}
3576
template<typename T> template<int EE> inline uint8_t CPUCore<T>::SLA_X(unsigned x) {
3577
	uint8_t res = SLA(RDMEM(x, T::CC_SET_XHL_1 + EE));
3578
	WRMEM(x, res, T::CC_SET_XHL_2 + EE);
3579
	return res;
3580
}
3581
template<typename T> template<Reg8 REG> II CPUCore<T>::sla_R() {
3582
	set8<REG>(SLA(get8<REG>())); return {1, T::CC_SET_R};
3583
}
3584
template<typename T> II CPUCore<T>::sla_xhl() {
3585
	SLA_X<0>(getHL()); return {1, T::CC_SET_XHL};
3586
}
3587
template<typename T> template<Reg8 REG> II CPUCore<T>::sla_xix_R(unsigned a) {
3588
	T::setMemPtr(a);
3589
	set8<REG>(SLA_X<T::CC_DD + T::EE_SET_XIX>(a));
3590
	return {3, T::CC_DD + T::CC_SET_XIX};
3591
}
3592
3593
// SLL r
3594
template<typename T> inline uint8_t CPUCore<T>::SLL(uint8_t reg) {
3595
	assert(!T::IS_R800); // this instruction is Z80-only
3596
	uint8_t c = reg >> 7;
3597
	reg = narrow_cast<uint8_t>((reg << 1) | 1);
3598
	uint8_t f = c ? C_FLAG : 0;
3599
	f |= table.ZSPXY[reg];
3600
	setF(f);
3601
	return reg;
3602
}
3603
template<typename T> template<int EE> inline uint8_t CPUCore<T>::SLL_X(unsigned x) {
3604
	uint8_t res = SLL(RDMEM(x, T::CC_SET_XHL_1 + EE));
3605
	WRMEM(x, res, T::CC_SET_XHL_2 + EE);
3606
	return res;
3607
}
3608
template<typename T> template<Reg8 REG> II CPUCore<T>::sll_R() {
3609
	set8<REG>(SLL(get8<REG>())); return {1, T::CC_SET_R};
3610
}
3611
template<typename T> II CPUCore<T>::sll_xhl() {
3612
	SLL_X<0>(getHL()); return {1, T::CC_SET_XHL};
3613
}
3614
template<typename T> template<Reg8 REG> II CPUCore<T>::sll_xix_R(unsigned a) {
3615
	T::setMemPtr(a);
3616
	set8<REG>(SLL_X<T::CC_DD + T::EE_SET_XIX>(a));
3617
	return {3, T::CC_DD + T::CC_SET_XIX};
3618
}
3619
template<typename T> II CPUCore<T>::sll2() {
3620
	assert(T::IS_R800); // this instruction is R800-only
3621
	uint8_t f = (getF() & (X_FLAG | Y_FLAG)) |
3622
	            (getA() >> 7) | // C_FLAG
3623
	            0; // all other flags zero
3624
	setF(f);
3625
	return {3, T::CC_DD + T::CC_SET_XIX}; // TODO
3626
}
3627
3628
// SRA r
3629
template<typename T> inline uint8_t CPUCore<T>::SRA(uint8_t reg) {
3630
	uint8_t c = reg & 1;
3631
	reg = (reg >> 1) | (reg & 0x80);
3632
	uint8_t f = c ? C_FLAG : 0;
3633
	if constexpr (T::IS_R800) {
3634
		f |= table.ZSP[reg];
3635
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3636
	} else {
3637
		f |= table.ZSPXY[reg];
3638
	}
3639
	setF(f);
3640
	return reg;
3641
}
3642
template<typename T> template<int EE> inline uint8_t CPUCore<T>::SRA_X(unsigned x) {
3643
	uint8_t res = SRA(RDMEM(x, T::CC_SET_XHL_1 + EE));
3644
	WRMEM(x, res, T::CC_SET_XHL_2 + EE);
3645
	return res;
3646
}
3647
template<typename T> template<Reg8 REG> II CPUCore<T>::sra_R() {
3648
	set8<REG>(SRA(get8<REG>())); return {1, T::CC_SET_R};
3649
}
3650
template<typename T> II CPUCore<T>::sra_xhl() {
3651
	SRA_X<0>(getHL()); return {1, T::CC_SET_XHL};
3652
}
3653
template<typename T> template<Reg8 REG> II CPUCore<T>::sra_xix_R(unsigned a) {
3654
	T::setMemPtr(a);
3655
	set8<REG>(SRA_X<T::CC_DD + T::EE_SET_XIX>(a));
3656
	return {3, T::CC_DD + T::CC_SET_XIX};
3657
}
3658
3659
// SRL R
3660
template<typename T> inline uint8_t CPUCore<T>::SRL(uint8_t reg) {
3661
	uint8_t c = reg & 1;
3662
	reg >>= 1;
3663
	uint8_t f = c ? C_FLAG : 0;
3664
	if constexpr (T::IS_R800) {
3665
		f |= table.ZSP[reg];
3666
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
3667
	} else {
3668
		f |= table.ZSPXY[reg];
3669
	}
3670
	setF(f);
3671
	return reg;
3672
}
3673
template<typename T> template<int EE> inline uint8_t CPUCore<T>::SRL_X(unsigned x) {
3674
	uint8_t res = SRL(RDMEM(x, T::CC_SET_XHL_1 + EE));
3675
	WRMEM(x, res, T::CC_SET_XHL_2 + EE);
3676
	return res;
3677
}
3678
template<typename T> template<Reg8 REG> II CPUCore<T>::srl_R() {
3679
	set8<REG>(SRL(get8<REG>())); return {1, T::CC_SET_R};
3680
}
3681
template<typename T> II CPUCore<T>::srl_xhl() {
3682
	SRL_X<0>(getHL()); return {1, T::CC_SET_XHL};
3683
}
3684
template<typename T> template<Reg8 REG> II CPUCore<T>::srl_xix_R(unsigned a) {
3685
	T::setMemPtr(a);
3686
	set8<REG>(SRL_X<T::CC_DD + T::EE_SET_XIX>(a));
3687
	return {3, T::CC_DD + T::CC_SET_XIX};
3688
}
3689
3690
// RLA RLCA RRA RRCA
3691
template<typename T> II CPUCore<T>::rla() {
3692
	uint8_t c = getF() & C_FLAG;
3693
	uint8_t f = (getA() & 0x80) ? C_FLAG : 0;
3694
	if constexpr (T::IS_R800) {
3695
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG | X_FLAG | Y_FLAG));
3696
	} else {
3697
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG));
3698
	}
3699
	setA(narrow_cast<uint8_t>((getA() << 1) | (c ? 1 : 0)));
3700
	if constexpr (!T::IS_R800) {
3701
		f |= uint8_t(getA() & (X_FLAG | Y_FLAG));
3702
	}
3703
	setF(f);
3704
	return {1, T::CC_RLA};
3705
}
3706
template<typename T> II CPUCore<T>::rlca() {
3707
	setA(narrow_cast<uint8_t>((getA() << 1) | (getA() >> 7)));
3708
	uint8_t f = 0;
3709
	if constexpr (T::IS_R800) {
3710
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG | X_FLAG | Y_FLAG));
3711
		f |= uint8_t(getA() & C_FLAG);
3712
	} else {
3713
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG));
3714
		f |= uint8_t(getA() & (Y_FLAG | X_FLAG | C_FLAG));
3715
	}
3716
	setF(f);
3717
	return {1, T::CC_RLA};
3718
}
3719
template<typename T> II CPUCore<T>::rra() {
3720
	auto c = uint8_t((getF() & C_FLAG) << 7);
3721
	uint8_t f = (getA() & 0x01) ? C_FLAG : 0;
3722
	if constexpr (T::IS_R800) {
3723
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG | X_FLAG | Y_FLAG));
3724
	} else {
3725
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG));
3726
	}
3727
	setA((getA() >> 1) | c);
3728
	if constexpr (!T::IS_R800) {
3729
		f |= uint8_t(getA() & (X_FLAG | Y_FLAG));
3730
	}
3731
	setF(f);
3732
	return {1, T::CC_RLA};
3733
}
3734
template<typename T> II CPUCore<T>::rrca() {
3735
	uint8_t f = getA() & C_FLAG;
3736
	if constexpr (T::IS_R800) {
3737
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG | X_FLAG | Y_FLAG));
3738
	} else {
3739
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG));
3740
	}
3741
	setA(narrow_cast<uint8_t>((getA() >> 1) | (getA() << 7)));
3742
	if constexpr (!T::IS_R800) {
3743
		f |= uint8_t(getA() & (X_FLAG | Y_FLAG));
3744
	}
3745
	setF(f);
3746
	return {1, T::CC_RLA};
3747
}
3748
3749
3750
// RLD
3751
template<typename T> II CPUCore<T>::rld() {
3752
	uint8_t val = RDMEM(getHL(), T::CC_RLD_1);
3753
	T::setMemPtr(getHL() + 1);
3754
	WRMEM(getHL(), narrow_cast<uint8_t>((val << 4) | (getA() & 0x0F)), T::CC_RLD_2);
3755
	setA((getA() & 0xF0) | (val >> 4));
3756
	uint8_t f = 0;
3757
	if constexpr (T::IS_R800) {
3758
		f |= uint8_t(getF() & (C_FLAG | X_FLAG | Y_FLAG));
3759
		f |= table.ZSP[getA()];
3760
	} else {
3761
		f |= uint8_t(getF() & C_FLAG);
3762
		f |= table.ZSPXY[getA()];
3763
	}
3764
	setF(f);
3765
	return {1, T::CC_RLD};
3766
}
3767
3768
// RRD
3769
template<typename T> II CPUCore<T>::rrd() {
3770
	uint8_t val = RDMEM(getHL(), T::CC_RLD_1);
3771
	T::setMemPtr(getHL() + 1);
3772
	WRMEM(getHL(), narrow_cast<uint8_t>((val >> 4) | (getA() << 4)), T::CC_RLD_2);
3773
	setA((getA() & 0xF0) | (val & 0x0F));
3774
	uint8_t f = 0;
3775
	if constexpr (T::IS_R800) {
3776
		f |= uint8_t(getF() & (C_FLAG | X_FLAG | Y_FLAG));
3777
		f |= table.ZSP[getA()];
3778
	} else {
3779
		f |= uint8_t(getF() & C_FLAG);
3780
		f |= table.ZSPXY[getA()];
3781
	}
3782
	setF(f);
3783
	return {1, T::CC_RLD};
3784
}
3785
3786
3787
// PUSH ss
3788
template<typename T> template<int EE> inline void CPUCore<T>::PUSH(uint16_t reg) {
3789
	setSP(getSP() - 2);
3790
	WR_WORD_rev<true, true>(getSP(), reg, T::CC_PUSH_1 + EE);
3791
}
3792
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::push_SS() {
3793
	PUSH<EE>(get16<REG>()); return {1, T::CC_PUSH + EE};
3794
}
3795
3796
// POP ss
3797
template<typename T> template<int EE> inline uint16_t CPUCore<T>::POP() {
3798
	uint16_t addr = getSP();
3799
	setSP(addr + 2);
3800
	if constexpr (T::IS_R800) {
3801
		// handles both POP and RET instructions (RET with condition = true)
3802
		if constexpr (EE == 0) { // not reti/retn, not pop ix/iy
3803
			setCurrentPopRet();
3804
			// No need for setSlowInstructions()
3805
			// -> this only matters directly after a CALL
3806
			//    instruction and in that case we're still
3807
			//    executing slow instructions.
3808
		}
3809
	}
3810
	return RD_WORD(addr, T::CC_POP_1 + EE);
3811
}
3812
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::pop_SS() {
3813
	set16<REG>(POP<EE>()); return {1, T::CC_POP + EE};
3814
}
3815
3816
3817
// CALL nn / CALL cc,nn
3818
template<typename T> template<typename COND> II CPUCore<T>::call(COND cond) {
3819
	uint16_t addr = RD_WORD_PC<1>(T::CC_CALL_1);
3820
	T::setMemPtr(addr);
3821
	if (cond(getF())) {
3822
		PUSH<T::EE_CALL>(getPC() + 3); /**/
3823
		setPC(addr);
3824
		if constexpr (T::IS_R800) {
3825
			setCurrentCall();
3826
			setSlowInstructions();
3827
		}
3828
		return {0/*3*/, T::CC_CALL_A};
3829
	} else {
3830
		return {3, T::CC_CALL_B};
3831
	}
3832
}
3833
3834
3835
// RST n
3836
template<typename T> template<unsigned ADDR> II CPUCore<T>::rst() {
3837
	PUSH<0>(getPC() + 1); /**/
3838
	T::setMemPtr(ADDR);
3839
	setPC(ADDR);
3840
	if constexpr (T::IS_R800) {
3841
		setCurrentCall();
3842
		setSlowInstructions();
3843
	}
3844
	return {0/*1*/, T::CC_RST};
3845
}
3846
3847
3848
// RET
3849
template<typename T> template<int EE, typename COND> inline II CPUCore<T>::RET(COND cond) {
3850
	if (cond(getF())) {
3851
		auto addr = POP<EE>();
3852
		T::setMemPtr(addr);
3853
		setPC(addr);
3854
		return {0/*1*/, T::CC_RET_A + EE};
3855
	} else {
3856
		return {1, T::CC_RET_B + EE};
3857
	}
3858
}
3859
template<typename T> template<typename COND> II CPUCore<T>::ret(COND cond) {
3860
	return RET<T::EE_RET_C>(cond);
3861
}
3862
template<typename T> II CPUCore<T>::ret() {
3863
	return RET<0>(CondTrue());
3864
}
3865
template<typename T> II CPUCore<T>::retn() { // also reti
3866
	setIFF1(getIFF2());
3867
	setSlowInstructions();
3868
	return RET<T::EE_RETN>(CondTrue());
3869
}
3870
3871
3872
// JP ss
3873
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::jp_SS() {
3874
	setPC(get16<REG>()); T::R800ForcePageBreak(); return {0/*1*/, T::CC_JP_HL + EE};
3875
}
3876
3877
// JP nn / JP cc,nn
3878
template<typename T> template<typename COND> II CPUCore<T>::jp(COND cond) {
3879
	uint16_t addr = RD_WORD_PC<1>(T::CC_JP_1);
3880
	T::setMemPtr(addr);
3881
	if (cond(getF())) {
3882
		setPC(addr);
3883
		T::R800ForcePageBreak();
3884
		return {0/*3*/, T::CC_JP_A};
3885
	} else {
3886
		return {3, T::CC_JP_B};
3887
	}
3888
}
3889
3890
// JR e
3891
template<typename T> template<typename COND> II CPUCore<T>::jr(COND cond) {
3892
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_JR_1);
3893
	if (cond(getF())) {
3894
		if (((getPC() + 2) & 0xFF) == 0) { /**/
3895
			// On R800, when this instruction is located in the
3896
			// last two byte of a page (a page is a 256-byte
3897
			// (aligned) memory block) and even if we jump back,
3898
			// thus fetching the next opcode byte does not cause a
3899
			// page-break, there still is one cycle overhead. It's
3900
			// as-if there is a page-break.
3901
			//
3902
			// This could be explained by some (very limited)
3903
			// pipeline behaviour in R800: it seems that the
3904
			// decision to cause a page-break on the next
3905
			// instruction is already made before the jump
3906
			// destination address for the current instruction is
3907
			// calculated (though a destination address in another
3908
			// page is also a reason for a page-break).
3909
			//
3910
			// It's likely all instructions behave like this, but I
3911
			// think we can get away with only explicitly emulating
3912
			// this behaviour in the djnz and the jr (conditional
3913
			// or not) instructions: all other instructions that
3914
			// cause the PC to change in a non-incremental way do
3915
			// already force a page-break for another reason, so
3916
			// this effect is masked. Examples of such instructions
3917
			// are: JP, RET, CALL, RST, all repeated block
3918
			// instructions, accepting an IRQ, (are there more
3919
			// instructions or events that change PC?)
3920
			//
3921
			// See doc/r800-djnz.txt for more details.
3922
			T::R800ForcePageBreak();
3923
		}
3924
		setPC(narrow_cast<uint16_t>(getPC() + 2 + ofst));
3925
		T::setMemPtr(getPC());
3926
		return {0/*2*/, T::CC_JR_A};
3927
	} else {
3928
		return {2, T::CC_JR_B};
3929
	}
3930
}
3931
3932
// DJNZ e
3933
template<typename T> II CPUCore<T>::djnz() {
3934
	uint8_t b = getB() - 1;
3935
	setB(b);
3936
	int8_t ofst = RDMEM_OPCODE<1>(T::CC_JR_1 + T::EE_DJNZ);
3937
	if (b) {
3938
		if (((getPC() + 2) & 0xFF) == 0) { /**/
3939
			// See comment in jr()
3940
			T::R800ForcePageBreak();
3941
		}
3942
		setPC(narrow_cast<uint16_t>(getPC() + 2 + ofst));
3943
		T::setMemPtr(getPC());
3944
		return {0/*2*/, T::CC_JR_A + T::EE_DJNZ};
3945
	} else {
3946
		return {2, T::CC_JR_B + T::EE_DJNZ};
3947
	}
3948
}
3949
3950
// EX (SP),ss
3951
template<typename T> template<Reg16 REG, int EE> II CPUCore<T>::ex_xsp_SS() {
3952
	uint16_t res = RD_WORD_impl<true, false>(getSP(), T::CC_EX_SP_HL_1 + EE);
3953
	T::setMemPtr(res);
3954
	WR_WORD_rev<false, true>(getSP(), get16<REG>(), T::CC_EX_SP_HL_2 + EE);
3955
	set16<REG>(res);
3956
	return {1, T::CC_EX_SP_HL + EE};
3957
}
3958
3959
// IN r,(c)
3960
template<typename T> template<Reg8 REG> II CPUCore<T>::in_R_c() {
3961
	if constexpr (T::IS_R800) T::waitForEvenCycle(T::CC_IN_R_C_1);
3962
	T::setMemPtr(getBC() + 1);
3963
	uint8_t res = READ_PORT(getBC(), T::CC_IN_R_C_1);
3964
	uint8_t f = 0;
3965
	if constexpr (T::IS_R800) {
3966
		f |= uint8_t(getF() & (C_FLAG | X_FLAG | Y_FLAG));
3967
		f |= table.ZSP[res];
3968
	} else {
3969
		f |= uint8_t(getF() & C_FLAG);
3970
		f |= table.ZSPXY[res];
3971
	}
3972
	setF(f);
3973
	set8<REG>(res);
3974
	return {1, T::CC_IN_R_C};
3975
}
3976
3977
// IN a,(n)
3978
template<typename T> II CPUCore<T>::in_a_byte() {
3979
	unsigned y = RDMEM_OPCODE<1>(T::CC_IN_A_N_1) + 256 * getA();
3980
	T::setMemPtr(y + 1);
3981
	if constexpr (T::IS_R800) T::waitForEvenCycle(T::CC_IN_A_N_2);
3982
	setA(READ_PORT(narrow_cast<uint16_t>(y), T::CC_IN_A_N_2));
3983
	return {2, T::CC_IN_A_N};
3984
}
3985
3986
// OUT (c),r
3987
template<typename T> template<Reg8 REG> II CPUCore<T>::out_c_R() {
3988
	if constexpr (T::IS_R800) T::waitForEvenCycle(T::CC_OUT_C_R_1);
3989
	T::setMemPtr(getBC() + 1);
3990
	WRITE_PORT(getBC(), get8<REG>(), T::CC_OUT_C_R_1);
3991
	return {1, T::CC_OUT_C_R};
3992
}
3993
template<typename T> II CPUCore<T>::out_c_0() {
3994
	// TODO not on R800
3995
	if constexpr (T::IS_R800) T::waitForEvenCycle(T::CC_OUT_C_R_1);
3996
	T::setMemPtr(getBC() + 1);
3997
	uint8_t out_c_x = isCMOS ? 255 : 0;
3998
	WRITE_PORT(getBC(), out_c_x, T::CC_OUT_C_R_1);
3999
	return {1, T::CC_OUT_C_R};
4000
}
4001
4002
// OUT (n),a
4003
template<typename T> II CPUCore<T>::out_byte_a() {
4004
	uint8_t port = RDMEM_OPCODE<1>(T::CC_OUT_N_A_1);
4005
	auto y = narrow_cast<uint16_t>((getA() << 8) | port);
4006
	T::setMemPtr((getA() << 8) | ((port + 1) & 255));
4007
	if constexpr (T::IS_R800) T::waitForEvenCycle(T::CC_OUT_N_A_2);
4008
	WRITE_PORT(y, getA(), T::CC_OUT_N_A_2);
4009
	return {2, T::CC_OUT_N_A};
4010
}
4011
4012
4013
// block CP
4014
template<typename T> inline II CPUCore<T>::BLOCK_CP(int increase, bool repeat) {
4015
	T::setMemPtr(T::getMemPtr() + increase);
4016
	uint8_t val = RDMEM(getHL(), T::CC_CPI_1);
4017
	uint8_t res = getA() - val;
4018
	setHL(narrow_cast<uint16_t>(getHL() + increase));
4019
	setBC(getBC() - 1);
4020
	uint8_t f = ((getA() ^ val ^ res) & H_FLAG) |
4021
	            table.ZS[res] |
4022
	            N_FLAG |
4023
	            (getBC() ? V_FLAG : 0);
4024
	if constexpr (T::IS_R800) {
4025
		f |= uint8_t(getF() & (C_FLAG | X_FLAG | Y_FLAG));
4026
	} else {
4027
		f |= uint8_t(getF() & C_FLAG);
4028
		unsigned k = res - ((f & H_FLAG) >> 4);
4029
		f |= (k << 4) & Y_FLAG; // bit 1 -> flag 5
4030
		f |= k & X_FLAG;        // bit 3 -> flag 3
4031
	}
4032
	setF(f);
4033
	if (repeat && getBC() && res) {
4034
		//setPC(getPC() - 2);
4035
		T::setMemPtr(getPC() + 1);
4036
		return {uint16_t(-1)/*1*/, T::CC_CPIR};
4037
	} else {
4038
		return {1, T::CC_CPI};
4039
	}
4040
}
4041
template<typename T> II CPUCore<T>::cpd()  { return BLOCK_CP(-1, false); }
4042
template<typename T> II CPUCore<T>::cpi()  { return BLOCK_CP( 1, false); }
4043
template<typename T> II CPUCore<T>::cpdr() { return BLOCK_CP(-1, true ); }
4044
template<typename T> II CPUCore<T>::cpir() { return BLOCK_CP( 1, true ); }
4045
4046
4047
// block LD
4048
template<typename T> inline II CPUCore<T>::BLOCK_LD(int increase, bool repeat) {
4049
	uint8_t val = RDMEM(getHL(), T::CC_LDI_1);
4050
	WRMEM(getDE(), val, T::CC_LDI_2);
4051
	setHL(narrow_cast<uint16_t>(getHL() + increase));
4052
	setDE(narrow_cast<uint16_t>(getDE() + increase));
4053
	setBC(getBC() - 1);
4054
	uint8_t f = getBC() ? V_FLAG : 0;
4055
	if constexpr (T::IS_R800) {
4056
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | C_FLAG | X_FLAG | Y_FLAG));
4057
	} else {
4058
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | C_FLAG));
4059
		f |= uint8_t(((getA() + val) << 4) & Y_FLAG); // bit 1 -> flag 5
4060
		f |= uint8_t((getA() + val) & X_FLAG);        // bit 3 -> flag 3
4061
	}
4062
	setF(f);
4063
	if (repeat && getBC()) {
4064
		//setPC(getPC() - 2);
4065
		T::setMemPtr(getPC() + 1);
4066
		return {uint16_t(-1)/*1*/, T::CC_LDIR};
4067
	} else {
4068
		return {1, T::CC_LDI};
4069
	}
4070
}
4071
template<typename T> II CPUCore<T>::ldd()  { return BLOCK_LD(-1, false); }
4072
template<typename T> II CPUCore<T>::ldi()  { return BLOCK_LD( 1, false); }
4073
template<typename T> II CPUCore<T>::lddr() { return BLOCK_LD(-1, true ); }
4074
template<typename T> II CPUCore<T>::ldir() { return BLOCK_LD( 1, true ); }
4075
4076
4077
// block IN
4078
template<typename T> inline II CPUCore<T>::BLOCK_IN(int increase, bool repeat) {
4079
	if constexpr (T::IS_R800) T::waitForEvenCycle(T::CC_INI_1);
4080
	T::setMemPtr(getBC() + increase);
4081
	setBC(getBC() - 0x100); // decr before use
4082
	uint8_t val = READ_PORT(getBC(), T::CC_INI_1);
4083
	WRMEM(getHL(), val, T::CC_INI_2);
4084
	setHL(narrow_cast<uint16_t>(getHL() + increase));
4085
	unsigned k = val + ((getC() + increase) & 0xFF);
4086
	uint8_t b = getB();
4087
	if constexpr (T::IS_R800) {
4088
		setF((getF() & ~Z_FLAG) | (b ? 0 : Z_FLAG) | N_FLAG);
4089
	} else {
4090
		setF(((val & S_FLAG) >> 6) | // N_FLAG
4091
		       ((k & 0x100) ? (H_FLAG | C_FLAG) : 0) |
4092
		       table.ZSXY[b] |
4093
		       (table.ZSPXY[(k & 0x07) ^ b] & P_FLAG));
4094
	}
4095
	if (repeat && b) {
4096
		//setPC(getPC() - 2);
4097
		return {uint16_t(-1)/*1*/, T::CC_INIR};
4098
	} else {
4099
		return {1, T::CC_INI};
4100
	}
4101
}
4102
template<typename T> II CPUCore<T>::ind()  { return BLOCK_IN(-1, false); }
4103
template<typename T> II CPUCore<T>::ini()  { return BLOCK_IN( 1, false); }
4104
template<typename T> II CPUCore<T>::indr() { return BLOCK_IN(-1, true ); }
4105
template<typename T> II CPUCore<T>::inir() { return BLOCK_IN( 1, true ); }
4106
4107
4108
// block OUT
4109
template<typename T> inline II CPUCore<T>::BLOCK_OUT(int increase, bool repeat) {
4110
	uint8_t val = RDMEM(getHL(), T::CC_OUTI_1);
4111
	setHL(narrow_cast<uint16_t>(getHL() + increase));
4112
	if constexpr (T::IS_R800) T::waitForEvenCycle(T::CC_OUTI_2);
4113
	WRITE_PORT(getBC(), val, T::CC_OUTI_2);
4114
	setBC(getBC() - 0x100); // decr after use
4115
	T::setMemPtr(getBC() + increase);
4116
	unsigned k = val + getL();
4117
	uint8_t b = getB();
4118
	if constexpr (T::IS_R800) {
4119
		setF((getF() & ~Z_FLAG) | (b ? 0 : Z_FLAG) | N_FLAG);
4120
	} else {
4121
		setF(((val & S_FLAG) >> 6) | // N_FLAG
4122
		       ((k & 0x100) ? (H_FLAG | C_FLAG) : 0) |
4123
		       table.ZSXY[b] |
4124
		       (table.ZSPXY[(k & 0x07) ^ b] & P_FLAG));
4125
	}
4126
	if (repeat && b) {
4127
		//setPC(getPC() - 2);
4128
		return {uint16_t(-1)/*1*/, T::CC_OTIR};
4129
	} else {
4130
		return {1, T::CC_OUTI};
4131
	}
4132
}
4133
template<typename T> II CPUCore<T>::outd() { return BLOCK_OUT(-1, false); }
4134
template<typename T> II CPUCore<T>::outi() { return BLOCK_OUT( 1, false); }
4135
template<typename T> II CPUCore<T>::otdr() { return BLOCK_OUT(-1, true ); }
4136
template<typename T> II CPUCore<T>::otir() { return BLOCK_OUT( 1, true ); }
4137
4138
4139
// various
4140
template<typename T> template<int EE> II CPUCore<T>::nop() { return {1, T::CC_NOP + EE}; }
4141
template<typename T> II CPUCore<T>::ccf() {
4142
	uint8_t f = 0;
4143
	if constexpr (T::IS_R800) {
4144
		// H flag is different from Z80 (and as always XY flags as well)
4145
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG | C_FLAG | X_FLAG | Y_FLAG | H_FLAG));
4146
	} else {
4147
		f |= uint8_t((getF() & C_FLAG) << 4); // H_FLAG
4148
		// only set X(Y) flag (don't reset if already set)
4149
		if (isCMOS) {
4150
			// Y flag is not changed on a CMOS Z80
4151
			f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG | C_FLAG | Y_FLAG));
4152
			f |= uint8_t((getF() | getA()) & X_FLAG);
4153
		} else {
4154
			f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG | C_FLAG));
4155
			f |= uint8_t((getF() | getA()) & (X_FLAG | Y_FLAG));
4156
		}
4157
	}
4158
	f ^= C_FLAG;
4159
	setF(f);
4160
	return {1, T::CC_CCF};
4161
}
4162
template<typename T> II CPUCore<T>::cpl() {
4163
	setA(getA() ^ 0xFF);
4164
	uint8_t f = H_FLAG | N_FLAG;
4165
	if constexpr (T::IS_R800) {
4166
		f |= getF();
4167
	} else {
4168
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG | C_FLAG));
4169
		f |= uint8_t(getA() & (X_FLAG | Y_FLAG));
4170
	}
4171
	setF(f);
4172
	return {1, T::CC_CPL};
4173
}
4174
template<typename T> II CPUCore<T>::daa() {
4175
	uint8_t a = getA();
4176
	uint8_t f = getF();
4177
	uint8_t adjust = 0;
4178
	if ((f & H_FLAG) || ((getA() & 0xf) > 9)) adjust += 6;
4179
	if ((f & C_FLAG) || (getA() > 0x99)) adjust += 0x60;
4180
	if (f & N_FLAG) a -= adjust; else a += adjust;
4181
	if constexpr (T::IS_R800) {
4182
		f &= C_FLAG | N_FLAG | X_FLAG | Y_FLAG;
4183
		f |= table.ZSP[a];
4184
	} else {
4185
		f &= C_FLAG | N_FLAG;
4186
		f |= table.ZSPXY[a];
4187
	}
4188
	f |= uint8_t((getA() > 0x99) | ((getA() ^ a) & H_FLAG));
4189
	setA(a);
4190
	setF(f);
4191
	return {1, T::CC_DAA};
4192
}
4193
template<typename T> II CPUCore<T>::neg() {
4194
	// alternative: LUT   uint16_t negTable[256]
4195
	unsigned a = getA();
4196
	unsigned res = -signed(a);
4197
	uint8_t f = ((res & 0x100) ? C_FLAG : 0) |
4198
	            N_FLAG |
4199
	            ((res ^ a) & H_FLAG) |
4200
	            ((a & res & 0x80) >> 5); // V_FLAG
4201
	if constexpr (T::IS_R800) {
4202
		f |= table.ZS[res & 0xFF];
4203
		f |= uint8_t(getF() & (X_FLAG | Y_FLAG));
4204
	} else {
4205
		f |= table.ZSXY[res & 0xFF];
4206
	}
4207
	setF(f);
4208
	setA(narrow_cast<uint8_t>(res));
4209
	return {1, T::CC_NEG};
4210
}
4211
template<typename T> II CPUCore<T>::scf() {
4212
	uint8_t f = C_FLAG;
4213
	if constexpr (T::IS_R800) {
4214
		f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG | X_FLAG | Y_FLAG));
4215
	} else {
4216
		// only set X(Y) flag (don't reset if already set)
4217
		if (isCMOS) {
4218
			// Y flag is not changed on a CMOS Z80
4219
			f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG | Y_FLAG));
4220
			f |= uint8_t((getF() | getA()) & X_FLAG);
4221
		} else {
4222
			f |= uint8_t(getF() & (S_FLAG | Z_FLAG | P_FLAG));
4223
			f |= uint8_t((getF() | getA()) & (X_FLAG | Y_FLAG));
4224
		}
4225
	}
4226
	setF(f);
4227
	return {1, T::CC_SCF};
4228
}
4229
4230
template<typename T> II CPUCore<T>::ex_af_af() {
4231
	auto t = getAF2(); setAF2(getAF()); setAF(t);
4232
	return {1, T::CC_EX};
4233
}
4234
template<typename T> II CPUCore<T>::ex_de_hl() {
4235
	auto t = getDE(); setDE(getHL()); setHL(t);
4236
	return {1, T::CC_EX};
4237
}
4238
template<typename T> II CPUCore<T>::exx() {
4239
	auto t1 = getBC2(); setBC2(getBC()); setBC(t1);
4240
	auto t2 = getDE2(); setDE2(getDE()); setDE(t2);
4241
	auto t3 = getHL2(); setHL2(getHL()); setHL(t3);
4242
	return {1, T::CC_EX};
4243
}
4244
4245
template<typename T> II CPUCore<T>::di() {
4246
	setIFF1(false);
4247
	setIFF2(false);
4248
	return {1, T::CC_DI};
4249
}
4250
template<typename T> II CPUCore<T>::ei() {
4251
	setIFF1(true);
4252
	setIFF2(true);
4253
	setCurrentEI(); // no ints directly after this instr
4254
	setSlowInstructions();
4255
	return {1, T::CC_EI};
4256
}
4257
template<typename T> II CPUCore<T>::halt() {
4258
	setHALT(true);
4259
	setSlowInstructions();
4260
4261
	if (!(getIFF1() || getIFF2())) {
4262
		diHaltCallback.execute();
4263
	}
4264
	return {1, T::CC_HALT};
4265
}
4266
template<typename T> template<unsigned N> II CPUCore<T>::im_N() {
4267
	setIM(N); return {1, T::CC_IM};
4268
}
4269
4270
// LD A,I/R
4271
template<typename T> template<Reg8 REG> II CPUCore<T>::ld_a_IR() {
4272
	setA(get8<REG>());
4273
	uint8_t f = getIFF2() ? V_FLAG : 0;
4274
	if constexpr (T::IS_R800) {
4275
		f |= uint8_t(getF() & (C_FLAG | X_FLAG | Y_FLAG));
4276
		f |= table.ZS[getA()];
4277
	} else {
4278
		f |= uint8_t(getF() & C_FLAG);
4279
		f |= table.ZSXY[getA()];
4280
		// see comment in the IRQ acceptance part of executeSlow().
4281
		setCurrentLDAI(); // only Z80 (not R800) has this quirk
4282
		setSlowInstructions();
4283
	}
4284
	setF(f);
4285
	return {1, T::CC_LD_A_I};
4286
}
4287
4288
// LD I/R,A
4289
template<typename T> II CPUCore<T>::ld_r_a() {
4290
	// This code sequence:
4291
	//   XOR A  /  LD R,A   / LD A,R
4292
	// gives A=2 for Z80, but A=1 for R800. The difference can possibly be
4293
	// explained by a difference in the relative time between writing the
4294
	// new value to the R register and increasing the R register per M1
4295
	// cycle. Here we implemented the R800 behaviour by storing 'A-1' into
4296
	// R, that's good enough for now.
4297
	uint8_t val = getA();
4298
	if constexpr (T::IS_R800) val -= 1;
4299
	setR(val);
4300
	return {1, T::CC_LD_A_I};
4301
}
4302
template<typename T> II CPUCore<T>::ld_i_a() {
4303
	setI(getA());
4304
	return {1, T::CC_LD_A_I};
4305
}
4306
4307
// MULUB A,r
4308
template<typename T> template<Reg8 REG> II CPUCore<T>::mulub_a_R() {
4309
	assert(T::IS_R800); // this instruction is R800-only
4310
	// Verified on real R800:
4311
	//   YHXN flags are unchanged
4312
	//   SV   flags are reset
4313
	//   Z    flag is set when result is zero
4314
	//   C    flag is set when result doesn't fit in 8-bit
4315
	setHL(uint16_t(getA()) * uint16_t(get8<REG>()));
4316
	setF((getF() & (N_FLAG | H_FLAG | X_FLAG | Y_FLAG)) |
4317
	       0 | // S_FLAG V_FLAG
4318
	       (getHL() ? 0 : Z_FLAG) |
4319
	       ((getHL() & 0xFF00) ? C_FLAG : 0));
4320
	return {1, T::CC_MULUB};
4321
}
4322
4323
// MULUW HL,ss
4324
template<typename T> template<Reg16 REG> II CPUCore<T>::muluw_hl_SS() {
4325
	assert(T::IS_R800); // this instruction is R800-only
4326
	// Verified on real R800:
4327
	//   YHXN flags are unchanged
4328
	//   SV   flags are reset
4329
	//   Z    flag is set when result is zero
4330
	//   C    flag is set when result doesn't fit in 16-bit
4331
	uint32_t res = uint32_t(getHL()) * get16<REG>();
4332
	setDE(narrow_cast<uint16_t>(res >> 16));
4333
	setHL(narrow_cast<uint16_t>(res >>  0));
4334
	setF((getF() & (N_FLAG | H_FLAG | X_FLAG | Y_FLAG)) |
4335
	       0 | // S_FLAG V_FLAG
4336
	       (res ? 0 : Z_FLAG) |
4337
	       ((res & 0xFFFF0000) ? C_FLAG : 0));
4338
	return {1, T::CC_MULUW};
4339
}
4340
4341
4342
// versions:
4343
//  1 -> initial version
4344
//  2 -> moved memptr from here to Z80TYPE (and not to R800TYPE)
4345
//  3 -> timing of the emulation changed (no changes in serialization)
4346
//  4 -> timing of the emulation changed again (see doc/internal/r800-call.txt)
4347
//  5 -> added serialization of nmiEdge
4348
template<typename T> template<typename Archive>
4349
void CPUCore<T>::serialize(Archive& ar, unsigned version)
4350
{
4351
	T::serialize(ar, version);
4352
	ar.serialize("regs", static_cast<CPURegs&>(*this));
4353
	if (ar.versionBelow(version, 2)) {
4354
		unsigned mPtr = 0; // dummy value (avoid warning)
4355
		ar.serialize("memptr", mPtr);
4356
		T::setMemPtr(mPtr);
4357
	}
4358
4359
	if (ar.versionBelow(version, 5)) {
4360
		// NMI is unused on MSX and even on systems where it is used nmiEdge
4361
		// is true only between the moment the NMI request comes in and the
4362
		// moment the Z80 jumps to the NMI handler, so defaulting to false
4363
		// is pretty safe.
4364
		nmiEdge = false;
4365
	} else {
4366
		// CPU is deserialized after devices, so nmiEdge is restored to the
4367
		// saved version even if IRQHelpers set it on deserialization.
4368
		ar.serialize("nmiEdge", nmiEdge);
4369
	}
4370
4371
	// Don't serialize:
4372
	// - IRQStatus, NMIStatus:
4373
	//     the IRQHelper deserialization makes sure these get the right value
4374
	// - slowInstructions, exitLoop:
4375
	//     serialization happens outside the CPU emulation loop
4376
4377
	if constexpr (T::IS_R800) {
4378
		if (ar.versionBelow(version, 4)) {
4379
			motherboard.getMSXCliComm().printWarning(
4380
				"Loading an old savestate: the timing of the R800 "
4381
				"emulation has changed. This may cause synchronization "
4382
				"problems in replay.");
4383
		}
4384
	}
4385
}
4386
4387
// Force template instantiation
4388
template class CPUCore<Z80TYPE>;
4389
template class CPUCore<R800TYPE>;
4390
4391
INSTANTIATE_SERIALIZE_METHODS(CPUCore<Z80TYPE>);
4392
INSTANTIATE_SERIALIZE_METHODS(CPUCore<R800TYPE>);
4393
4394
} // namespace openmsx