1 // $package. http://www.slack.net/~ant/
2 
3 // Last validated with zexall 2009.12.05.
4 // Doesn't implement the R register or immediate interrupt after EI.
5 // Address wrap-around isn't completely correct, but is prevented from crashing emulator.
6 // 16-bit memory accesses are made directly to mapped memory, instead of using macro.
7 
8 #if 0
9 /* Define these macros in the source file before #including this file.
10 - Parameters might be expressions, so they are best evaluated only once,
11 though they NEVER have side-effects, so multiple evaluation is OK.
12 - Output parameters might be a multiple-assignment expression like "a=x",
13 so they must NOT be parenthesized.
14 - Except where noted, time() and related functions will NOT work
15 correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and
16 CACHE_TIME() the normal time changing functions can be used.
17 - Macros "returning" void may use a {} statement block. */
18 
19     // 0 <= addr <= 0xFFFF + 0x100
20     // Optional; default uses whatever was set with map_mem()
21     int  READ_CODE( addr_t );
22 
23     // 0 <= addr <= 0xFFFF + 0x100
24 	// Optional; default uses whatever was set with map_mem()
25 	int  READ_MEM(  addr_t );
26 	void WRITE_MEM( addr_t, int data );
27 
28 	// 0 <= port <= 0xFFFF (apparently upper 8 bits are output by hardware)
29 	void OUT_PORT( int port, int data );
30 	int  IN_PORT   int port );
31 
32 	// Reference to Z80_Cpu object used for emulation
33 	#define CPU cpu
34 
35 // The following can be used within macros:
36 
37 	// Current time
38 	time_t TIME();
39 
40 	// Allows use of time functions
41 	void FLUSH_TIME();
42 
43 	// Must be used before end of macro if FLUSH_TIME() was used earlier
44 	void CACHE_TIME();
45 
46 // Configuration (optional; commented behavior if defined)
47 
48 	// Optimizes as if map_mem( 0, 0x10000, FLAT_MEM, FLAT_MEM ) is always in effect
49     #define FLAT_MEM my_mem_array
50 
51 	// If RST 7 ($FF) is encountered and PC = IDLE_ADDR, stops execution
52 	#define IDLE_ADDR 0x1234
53 
54 	// Expanded just before beginning of code, to help debugger
55 	#define CPU_BEGIN void my_run_cpu() {
56 
57 #endif
58 
59 /* Copyright (C) 2006-2008 Shay Green. This module is free software; you
60 can redistribute it and/or modify it under the terms of the GNU Lesser
61 General Public License as published by the Free Software Foundation; either
62 version 2.1 of the License, or (at your option) any later version. This
63 module is distributed in the hope that it will be useful, but WITHOUT ANY
64 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
65 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
66 details. You should have received a copy of the GNU Lesser General Public
67 License along with this module; if not, write to the Free Software Foundation,
68 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
69 
70 #ifdef CPU_BEGIN
71 	CPU_BEGIN
72 #endif
73 
74 #define R CPU.r
75 
76 // flags, named with hex value for clarity
77 int const S80 = 0x80;
78 int const Z40 = 0x40;
79 int const F20 = 0x20;
80 int const H10 = 0x10;
81 int const F08 = 0x08;
82 int const V04 = 0x04;
83 int const P04 = 0x04;
84 int const N02 = 0x02;
85 int const C01 = 0x01;
86 
87 #define SZ28P( n )  CPU.szpc [n]
88 #define SZ28PC( n ) CPU.szpc [n]
89 #define SZ28C( n )  (CPU.szpc [n] & ~P04)
90 #define SZ28( n )   SZ28C( n )
91 
92 #define SET_R( n )  (void) (R.r = n)
93 #define GET_R()     (R.r)
94 
95 // Time
96 #define TIME()          (s_time + s.base)
97 #define FLUSH_TIME()    {s.time = s_time;}
98 #define CACHE_TIME()    {s_time = s.time;}
99 
100 // Memory
101 #define RW_MEM( addr, rw )          RW_PAGE( addr, rw ) [RW_OFFSET( addr )]
102 #ifndef READ_CODE
103     #define READ_CODE( addr )       RW_MEM( addr, read )
104 #endif
105 
106 #ifdef FLAT_MEM
107 	#define RW_PAGE( addr, rw )     FLAT_MEM
108 	#define RW_OFFSET( addr )       (addr)
109 	#define INSTR( off, addr )      READ_CODE( addr )
110 #else
111 	#define RW_PAGE( addr, rw )     s.rw [(unsigned) (addr) >> Z80_Cpu::page_bits]
112 	#define RW_OFFSET( addr )       Z80_CPU_OFFSET( addr )
113 	#define INSTR( off, addr )      instr [off]
114 #endif
115 
116 #ifndef READ_MEM
117 	#define READ_MEM( addr )        RW_MEM( addr, read )
118 #endif
119 
120 #ifndef WRITE_MEM
121 	#define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data)
122 #endif
123 
124 #define READ_WORD( addr )           GET_LE16( &RW_MEM( addr, read ) )
125 #define WRITE_WORD( addr, data )    SET_LE16( &RW_MEM( addr, write ), data )
126 
127 // Truncation
128 #define BYTE(  n ) ((BOOST::uint8_t ) (n)) /* (unsigned) n & 0xFF */
129 #define SBYTE( n ) ((BOOST::int8_t  ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */
130 #define WORD(  n ) ((BOOST::uint16_t) (n)) /* (unsigned) n & 0xFFFF */
131 
132 // Misc
133 #define CASE5( a, b, c, d, e          ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e
134 #define CASE6( a, b, c, d, e, f       ) CASE5( a, b, c, d, e       ): case 0x##f
135 #define CASE7( a, b, c, d, e, f, g    ) CASE6( a, b, c, d, e, f    ): case 0x##g
136 #define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h
137 
138 #if BLARGG_BIG_ENDIAN
139 	#define R8( n, offset ) ((r.r8_ - offset) [n])
140 #elif BLARGG_LITTLE_ENDIAN
141 	#define R8( n, offset ) ((r.r8_ - offset) [(n) ^ 1])
142 #else
143 	#error "Byte order of CPU must be known"
144 #endif
145 
146 #define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)])
147 
148 #define EX( x, y ) \
149 	{\
150 		int temp = x;\
151 		x = y;\
152 		y = temp;\
153 	}
154 
155 #define EXX( name ) \
156 	EX( R.alt.name, r.name )
157 
158 bool warning = false;
159 {
160 	Z80_Cpu::cpu_state_t s;
161 	#ifdef FLAT_MEM
162 		s.base = CPU.cpu_state_.base;
163 	#else
164 		s = CPU.cpu_state_;
165 	#endif
166 	CPU.cpu_state = &s;
167 
168 
169 	union r_t {
170 		Z80_Cpu::regs_t b;
171 		Z80_Cpu::pairs_t w;
172 		byte r8_ [8]; // indexed
173 		BOOST::uint16_t r16_ [4];
174 	} r;
175 	r.b = R.b;
176 
177 	Z80_Cpu::time_t s_time = CPU.cpu_state_.time;
178 	int pc = R.pc;
179 	int sp = R.sp;
180 	int ix = R.ix; // TODO: keep in memory for direct access?
181 	int iy = R.iy;
182 	int flags = R.b.flags;
183 
184 	//goto loop; // confuses optimizer
185 	s_time += 7;
186 	pc -= 2;
187 
188 call_not_taken:
189 	s_time -= 7;
190 jp_not_taken:
191 	pc += 2;
192 loop:
193 
194 	check( (unsigned) pc < 0x10000 + 1 ); // +1 so emulator can catch wrap-around
195 	check( (unsigned) sp < 0x10000 );
196 	check( (unsigned) flags < 0x100 );
197 	check( (unsigned) ix < 0x10000 );
198 	check( (unsigned) iy < 0x10000 );
199 
200     byte const* instr = RW_PAGE( pc, read );
201 
202     int opcode;
203 
204     if ( RW_OFFSET( ~0 ) == ~0 )
205     {
206         opcode = instr [RW_OFFSET( pc )];
207         pc++;
208         instr += RW_OFFSET( pc );
209     }
210     else
211     {
212         instr += RW_OFFSET( pc );
213         opcode = *instr++;
214         pc++;
215     }
216 
217     static byte const clock_table [256 * 2] = {
218 	//   0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
219 		 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0
220 		 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1
221 		 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, // 2
222 		 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, // 3
223 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4
224 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5
225 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6
226 		 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7
227 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8
228 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9
229 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A
230 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B
231 		11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C
232 		11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D
233 		11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E
234 		11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F
235 
236 		// high four bits are $ED time - 8, low four bits are $DD/$FD time - 8
237 		//0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
238 		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
239 		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
240 		0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00,
241 		0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
242 		0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,
243 		0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,
244 		0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,
245 		0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00,
246 		0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,
247 		0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,
248 		0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,
249 		0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,
250 		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,
251 		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
252 		0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
253 		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
254 	};
255 
256 	if ( s_time >= 0 )
257 		goto out_of_time;
258 	s_time += clock_table [opcode];
259 
260 	#ifdef Z80_CPU_LOG_H
261 		//log_opcode( opcode, READ_CODE( pc ) );
262 		z80_cpu_log( "log.txt", pc - 1, opcode, READ_CODE( pc ),
263 				READ_CODE( pc + 1 ), READ_CODE( pc + 2 ) );
264 		z80_log_regs( r.b.a, r.w.bc, r.w.de, r.w.hl, sp, ix, iy );
265 	#endif
266 
267 #define GET_ADDR()  GET_LE16( &INSTR( 0, pc ) )
268 
269 	int data;
270     data = INSTR( 0, pc );
271 
272 	switch ( opcode )
273 	{
274 // Common
275 
276 	case 0x00: // NOP
277 	CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc.
278 		goto loop;
279 
280 	case 0x08:{// EX AF,AF'
281 		EXX( b.a );
282 		EX( R.alt.b.flags, flags );
283 		goto loop;
284 	}
285 
286 	case 0xD3: // OUT (imm),A
287 		pc++;
288 		OUT_PORT( (data + r.b.a * 0x100), r.b.a );
289 		goto loop;
290 
291 	case 0x2E: // LD L,imm
292 		pc++;
293 		r.b.l = data;
294 		goto loop;
295 
296 	case 0x3E: // LD A,imm
297 		pc++;
298 		r.b.a = data;
299 		goto loop;
300 
301 	case 0x3A:{// LD A,(addr)
302 		int addr = GET_ADDR();
303 		pc += 2;
304 		r.b.a = READ_MEM( addr );
305 		goto loop;
306 	}
307 
308 // Conditional
309 
310 #define ZERO    (flags & Z40)
311 #define CARRY   (flags & C01)
312 #define EVEN    (flags & P04)
313 #define MINUS   (flags & S80)
314 
315 // JR
316 // TODO: more efficient way to handle negative branch that wraps PC around
317 #define JR_( cond, clocks ) {\
318 	pc++;\
319 	if ( !(cond) )\
320 		goto loop;\
321 	int offset = SBYTE( data );\
322 	pc = WORD( pc + offset );\
323 	s_time += clocks;\
324 	goto loop;\
325 }
326 
327 #define JR( cond ) JR_( cond, 5 )
328 
329 	case 0x20: JR( !ZERO  ) // JR NZ,disp
330 	case 0x28: JR(  ZERO  ) // JR Z,disp
331 	case 0x30: JR( !CARRY ) // JR NC,disp
332 	case 0x38: JR(  CARRY ) // JR C,disp
333 	case 0x18: JR_( true,0) // JR disp
334 
335 	case 0x10:{// DJNZ disp
336 		int temp = r.b.b - 1;
337 		r.b.b = temp;
338 		JR( temp )
339 	}
340 
341 // JP
342 #define JP( cond ) \
343 	if ( !(cond) )\
344 		goto jp_not_taken;\
345 	pc = GET_ADDR();\
346 	goto loop;
347 
348 	case 0xC2: JP( !ZERO  ) // JP NZ,addr
349 	case 0xCA: JP(  ZERO  ) // JP Z,addr
350 	case 0xD2: JP( !CARRY ) // JP NC,addr
351 	case 0xDA: JP(  CARRY ) // JP C,addr
352 	case 0xE2: JP( !EVEN  ) // JP PO,addr
353 	case 0xEA: JP(  EVEN  ) // JP PE,addr
354 	case 0xF2: JP( !MINUS ) // JP P,addr
355 	case 0xFA: JP(  MINUS ) // JP M,addr
356 
357 	case 0xC3: // JP addr
358 		pc = GET_ADDR();
359 		goto loop;
360 
361 	case 0xE9: // JP HL
362 		pc = r.w.hl;
363 		goto loop;
364 
365 // RET
366 #define RET( cond ) \
367 	if ( cond )\
368 		goto ret_taken;\
369 	s_time -= 6;\
370 	goto loop;
371 
372 	case 0xC0: RET( !ZERO  ) // RET NZ
373 	case 0xC8: RET(  ZERO  ) // RET Z
374 	case 0xD0: RET( !CARRY ) // RET NC
375 	case 0xD8: RET(  CARRY ) // RET C
376 	case 0xE0: RET( !EVEN  ) // RET PO
377 	case 0xE8: RET(  EVEN  ) // RET PE
378 	case 0xF0: RET( !MINUS ) // RET P
379 	case 0xF8: RET(  MINUS ) // RET M
380 
381 	case 0xC9: // RET
382 	ret_taken:
383 		pc = READ_WORD( sp );
384 		sp = WORD( sp + 2 );
385 		goto loop;
386 
387 // CALL
388 #define CALL( cond ) \
389 	if ( cond )\
390 		goto call_taken;\
391 	goto call_not_taken;
392 
393 	case 0xC4: CALL( !ZERO  ) // CALL NZ,addr
394 	case 0xCC: CALL(  ZERO  ) // CALL Z,addr
395 	case 0xD4: CALL( !CARRY ) // CALL NC,addr
396 	case 0xDC: CALL(  CARRY ) // CALL C,addr
397 	case 0xE4: CALL( !EVEN  ) // CALL PO,addr
398 	case 0xEC: CALL(  EVEN  ) // CALL PE,addr
399 	case 0xF4: CALL( !MINUS ) // CALL P,addr
400 	case 0xFC: CALL(  MINUS ) // CALL M,addr
401 
402 	case 0xCD:{// CALL addr
403 	call_taken:
404 		int addr = pc + 2;
405 		pc = GET_ADDR();
406 		sp = WORD( sp - 2 );
407 		WRITE_WORD( sp, addr );
408 		goto loop;
409 	}
410 
411 	case 0xFF: // RST
412 		#ifdef IDLE_ADDR
413 			if ( pc == IDLE_ADDR + 1 )
414 				goto hit_idle_addr;
415 		#else
416 			if ( pc > 0x10000 )
417 			{
418 				pc = WORD( pc - 1 );
419 				s_time -= 11;
420 				goto loop;
421 			}
422 		#endif
423 	CASE7( C7, CF, D7, DF, E7, EF, F7 ):
424 		data = pc;
425 		pc = opcode & 0x38;
426 		#ifdef RST_BASE
427 			pc += RST_BASE;
428 		#endif
429 		goto push_data;
430 
431 // PUSH/POP
432 	case 0xF5: // PUSH AF
433 		data = r.b.a * 0x100u + flags;
434 		goto push_data;
435 
436 	case 0xC5: // PUSH BC
437 	case 0xD5: // PUSH DE
438 	case 0xE5: // PUSH HL
439 		data = R16( opcode, 4, 0xC5 );
440 	push_data:
441 		sp = WORD( sp - 2 );
442 		WRITE_WORD( sp, data );
443 		goto loop;
444 
445 	case 0xF1: // POP AF
446 		flags = READ_MEM( sp );
447 		r.b.a = READ_MEM( (sp + 1) );
448 		sp = WORD( sp + 2 );
449 		goto loop;
450 
451 	case 0xC1: // POP BC
452 	case 0xD1: // POP DE
453 	case 0xE1: // POP HL
454 		R16( opcode, 4, 0xC1 ) = READ_WORD( sp );
455 		sp = WORD( sp + 2 );
456 		goto loop;
457 
458 // ADC/ADD/SBC/SUB
459 	case 0x96: // SUB (HL)
460 	case 0x86: // ADD (HL)
461 		flags &= ~C01;
462 	case 0x9E: // SBC (HL)
463 	case 0x8E: // ADC (HL)
464 		data = READ_MEM( r.w.hl );
465 		goto adc_data;
466 
467 	case 0xD6: // SUB A,imm
468 	case 0xC6: // ADD imm
469 		flags &= ~C01;
470 	case 0xDE: // SBC A,imm
471 	case 0xCE: // ADC imm
472 		pc++;
473 		goto adc_data;
474 
475 	CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r
476 	CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r
477 		flags &= ~C01;
478 	CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r
479 	CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r
480 		data = R8( opcode & 7, 0 );
481 	adc_data: {
482 		int result = data + (flags & C01);
483 		data ^= r.b.a;
484 		flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes
485 		if ( flags )
486 			result = -result;
487 		result += r.b.a;
488 		data ^= result;
489 		flags +=(data & H10) +
490 				((data + 0x80) >> 6 & V04) +
491 				SZ28C( result & 0x1FF );
492 		r.b.a = result;
493 		goto loop;
494 	}
495 
496 // CP
497 	case 0xBE: // CP (HL)
498 		data = READ_MEM( r.w.hl );
499 		goto cp_data;
500 
501 	case 0xFE: // CP imm
502 		pc++;
503 		goto cp_data;
504 
505 	CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r
506 		data = R8( opcode, 0xB8 );
507 	cp_data: {
508 		int result = r.b.a - data;
509 		flags = N02 + (data & (F20 | F08)) + (result >> 8 & C01);
510 		data ^= r.b.a;
511 		flags +=(((result ^ r.b.a) & data) >> 5 & V04) +
512 				(((data & H10) ^ result) & (S80 | H10));
513 		if ( BYTE( result ) )
514 			goto loop;
515 		flags += Z40;
516 		goto loop;
517 	}
518 
519 // ADD HL,r.w
520 
521 	case 0x39: // ADD HL,SP
522 		data = sp;
523 		goto add_hl_data;
524 
525 	case 0x09: // ADD HL,BC
526 	case 0x19: // ADD HL,DE
527 	case 0x29: // ADD HL,HL
528 		data = R16( opcode, 4, 0x09 );
529 	add_hl_data: {
530 		int sum = r.w.hl + data;
531 		data ^= r.w.hl;
532 		r.w.hl = sum;
533 		flags = (flags & (S80 | Z40 | V04)) +
534 				(sum >> 16) +
535 				(sum >> 8 & (F20 | F08)) +
536 				((data ^ sum) >> 8 & H10);
537 		goto loop;
538 	}
539 
540 	case 0x27:{// DAA
541 		int a = r.b.a;
542 		if ( a > 0x99 )
543 			flags |= C01;
544 
545 		int adjust = 0x60 * (flags & C01);
546 
547 		if ( flags & H10 || (a & 0x0F) > 9 )
548 			adjust += 0x06;
549 
550 		if ( flags & N02 )
551 			adjust = -adjust;
552 		a += adjust;
553 
554 		flags = (flags & (C01 | N02)) +
555 				((r.b.a ^ a) & H10) +
556 				SZ28P( BYTE( a ) );
557 		r.b.a = a;
558 		goto loop;
559 	}
560 
561 // INC/DEC
562 	case 0x34: // INC (HL)
563 		data = READ_MEM( r.w.hl ) + 1;
564 		WRITE_MEM( r.w.hl, data );
565 		goto inc_set_flags;
566 
567 	CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r
568 		data = ++R8( opcode >> 3, 0 );
569 	inc_set_flags:
570 		flags = (flags & C01) +
571 				(((data & 0x0F) - 1) & H10) +
572 				SZ28( BYTE( data ) );
573 		if ( data != 0x80 )
574 			goto loop;
575 		flags += V04;
576 		goto loop;
577 
578 	case 0x35: // DEC (HL)
579 		data = READ_MEM( r.w.hl ) - 1;
580 		WRITE_MEM( r.w.hl, data );
581 		goto dec_set_flags;
582 
583 	CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r
584 		data = --R8( opcode >> 3, 0 );
585 	dec_set_flags:
586 		flags = (flags & C01) + N02 +
587 				(((data & 0x0F) + 1) & H10) +
588 				SZ28( BYTE( data ) );
589 		if ( data != 0x7F )
590 			goto loop;
591 		flags += V04;
592 		goto loop;
593 
594 	case 0x03: // INC BC
595 	case 0x13: // INC DE
596 	case 0x23: // INC HL
597 		R16( opcode, 4, 0x03 )++;
598 		goto loop;
599 
600 	case 0x33: // INC SP
601 		sp = WORD( sp + 1 );
602 		goto loop;
603 
604 	case 0x0B: // DEC BC
605 	case 0x1B: // DEC DE
606 	case 0x2B: // DEC HL
607 		R16( opcode, 4, 0x0B )--;
608 		goto loop;
609 
610 	case 0x3B: // DEC SP
611 		sp = WORD( sp - 1 );
612 		goto loop;
613 
614 // AND
615 	case 0xA6: // AND (HL)
616 		data = READ_MEM( r.w.hl );
617 		goto and_data;
618 
619 	case 0xE6: // AND imm
620 		pc++;
621 		goto and_data;
622 
623 	CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r
624 		data = R8( opcode, 0xA0 );
625 	and_data:
626 		r.b.a &= data;
627 		flags = SZ28P( r.b.a ) + H10;
628 		goto loop;
629 
630 // OR
631 	case 0xB6: // OR (HL)
632 		data = READ_MEM( r.w.hl );
633 		goto or_data;
634 
635 	case 0xF6: // OR imm
636 		pc++;
637 		goto or_data;
638 
639 	CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r
640 		data = R8( opcode, 0xB0 );
641 	or_data:
642 		r.b.a |= data;
643 		flags = SZ28P( r.b.a );
644 		goto loop;
645 
646 // XOR
647 	case 0xAE: // XOR (HL)
648 		data = READ_MEM( r.w.hl );
649 		goto xor_data;
650 
651 	case 0xEE: // XOR imm
652 		pc++;
653 		goto xor_data;
654 
655 	CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r
656 		data = R8( opcode, 0xA8 );
657 	xor_data:
658 		r.b.a ^= data;
659 		flags = SZ28P( r.b.a );
660 		goto loop;
661 
662 // LD
663 	CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r
664 		WRITE_MEM( r.w.hl, R8( opcode, 0x70 ) );
665 		goto loop;
666 
667 	CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r
668 	CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r
669 	CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r
670 	CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r
671 	CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r
672 	CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r
673 	CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r
674 		R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 );
675 		goto loop;
676 
677 	CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm
678 		R8( opcode >> 3, 0 ) = data;
679 		pc++;
680 		goto loop;
681 
682 	case 0x36: // LD (HL),imm
683 		pc++;
684 		WRITE_MEM( r.w.hl, data );
685 		goto loop;
686 
687 	CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL)
688 		R8( opcode >> 3, 8 ) = READ_MEM( r.w.hl );
689 		goto loop;
690 
691 	case 0x01: // LD r.w,imm
692 	case 0x11:
693 	case 0x21:
694 		R16( opcode, 4, 0x01 ) = GET_ADDR();
695 		pc += 2;
696 		goto loop;
697 
698 	case 0x31: // LD sp,imm
699 		sp = GET_ADDR();
700 		pc += 2;
701 		goto loop;
702 
703 	case 0x2A:{// LD HL,(addr)
704 		int addr = GET_ADDR();
705 		pc += 2;
706 		r.w.hl = READ_WORD( addr );
707 		goto loop;
708 	}
709 
710 	case 0x32:{// LD (addr),A
711 		int addr = GET_ADDR();
712 		pc += 2;
713 		WRITE_MEM( addr, r.b.a );
714 		goto loop;
715 	}
716 
717 	case 0x22:{// LD (addr),HL
718 		int addr = GET_ADDR();
719 		pc += 2;
720 		WRITE_WORD( addr, r.w.hl );
721 		goto loop;
722 	}
723 
724 	case 0x02: // LD (BC),A
725 	case 0x12: // LD (DE),A
726 		WRITE_MEM( R16( opcode, 4, 0x02 ), r.b.a );
727 		goto loop;
728 
729 	case 0x0A: // LD A,(BC)
730 	case 0x1A: // LD A,(DE)
731 		r.b.a = READ_MEM( R16( opcode, 4, 0x0A ) );
732 		goto loop;
733 
734 	case 0xF9: // LD SP,HL
735 		sp = r.w.hl;
736 		goto loop;
737 
738 // Rotate
739 
740 	case 0x07:{// RLCA
741 		int temp = r.b.a;
742 		temp = (temp << 1) + (temp >> 7);
743 		flags = (flags & (S80 | Z40 | P04)) +
744 				(temp & (F20 | F08 | C01));
745 		r.b.a = temp;
746 		goto loop;
747 	}
748 
749 	case 0x0F:{// RRCA
750 		int temp = r.b.a;
751 		flags = (flags & (S80 | Z40 | P04)) +
752 				(temp & C01);
753 		temp = (temp << 7) + (temp >> 1);
754 		flags += temp & (F20 | F08);
755 		r.b.a = temp;
756 		goto loop;
757 	}
758 
759 	case 0x17:{// RLA
760 		int temp = (r.b.a << 1) + (flags & C01);
761 		flags = (flags & (S80 | Z40 | P04)) +
762 				(temp & (F20 | F08)) +
763 				(temp >> 8);
764 		r.b.a = temp;
765 		goto loop;
766 	}
767 
768 	case 0x1F:{// RRA
769 		int temp = (flags << 7) + (r.b.a >> 1);
770 		flags = (flags & (S80 | Z40 | P04)) +
771 				(temp & (F20 | F08)) +
772 				(r.b.a & C01);
773 		r.b.a = temp;
774 		goto loop;
775 	}
776 
777 // Misc
778 	case 0x2F:{// CPL
779 		int temp = ~r.b.a;
780 		flags = (flags & (S80 | Z40 | P04 | C01)) +
781 				(temp & (F20 | F08)) +
782 				(H10 | N02);
783 		r.b.a = temp;
784 		goto loop;
785 	}
786 
787 	case 0x3F:{// CCF
788 		flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) +
789 				(flags << 4 & H10) +
790 				(r.b.a & (F20 | F08));
791 		goto loop;
792 	}
793 
794 	case 0x37: // SCF
795 		flags = (flags & (S80 | Z40 | P04)) | C01 +
796 				(r.b.a & (F20 | F08));
797 		goto loop;
798 
799 	case 0xDB: // IN A,(imm)
800 		pc++;
801 		r.b.a = IN_PORT( (data + r.b.a * 0x100) );
802 		goto loop;
803 
804 	case 0xE3:{// EX (SP),HL
805 		int temp = READ_WORD( sp );
806 		WRITE_WORD( sp, r.w.hl );
807 		r.w.hl = temp;
808 		goto loop;
809 	}
810 
811 	case 0xEB: // EX DE,HL
812 		EX( r.w.hl, r.w.de );
813 		goto loop;
814 
815 	case 0xD9: // EXX DE,HL
816 		EXX( w.bc );
817 		EXX( w.de );
818 		EXX( w.hl );
819 		goto loop;
820 
821 	case 0xF3: // DI
822 		R.iff1 = 0;
823 		R.iff2 = 0;
824 		goto loop;
825 
826 	case 0xFB: // EI
827 		R.iff1 = 1;
828 		R.iff2 = 1;
829 		// TODO: delayed effect
830 		goto loop;
831 
832 	case 0x76: // HALT
833 		goto halt;
834 
835 //////////////////////////////////////// CB prefix
836 	{
837 	case 0xCB:
838 		pc++;
839 		switch ( data )
840 		{
841 
842 	// Rotate left
843 
844 	#define RLC( read, write ) {\
845 		int result = read;\
846 		result = BYTE( result << 1 ) + (result >> 7);\
847 		flags = SZ28P( result ) + (result & C01);\
848 		write;\
849 		goto loop;\
850 	}
851 
852 		case 0x06: // RLC (HL)
853 			s_time += 7;
854 			data = r.w.hl;
855 		rlc_data_addr:
RLC(READ_MEM (data),WRITE_MEM (data,result))856 			RLC( READ_MEM( data ), WRITE_MEM( data, result ) )
857 
858 		CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r
859 			byte& reg = R8( data, 0 );
860 			RLC( reg, reg = result )
861 		}
862 
863 	#define RL( read, write ) {\
864 		int result = (read << 1) + (flags & C01);\
865 		flags = SZ28PC( result );\
866 		write;\
867 		goto loop;\
868 	}
869 
870 		case 0x16: // RL (HL)
871 			s_time += 7;
872 			data = r.w.hl;
873 		rl_data_addr:
RL(READ_MEM (data),WRITE_MEM (data,result))874 			RL( READ_MEM( data ), WRITE_MEM( data, result ) )
875 
876 		CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r
877 			byte& reg = R8( data, 0x10 );
878 			RL( reg, reg = result )
879 		}
880 
881 	#define SLA( read, low_bit, write ) {\
882 		int result = (read << 1) + low_bit;\
883 		flags = SZ28PC( result );\
884 		write;\
885 		goto loop;\
886 	}
887 
888 		case 0x26: // SLA (HL)
889 			s_time += 7;
890 			data = r.w.hl;
891 		sla_data_addr:
READ_MEM(data)892 			SLA( READ_MEM( data ), 0, WRITE_MEM( data, result ) )
893 
894 		CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r
895 			byte& reg = R8( data, 0x20 );
896 			SLA( reg, 0, reg = result )
897 		}
898 
899 		case 0x36: // SLL (HL)
900 			s_time += 7;
901 			data = r.w.hl;
902 		sll_data_addr:
READ_MEM(data)903 			SLA( READ_MEM( data ), 1, WRITE_MEM( data, result ) )
904 
905 		CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r
906 			byte& reg = R8( data, 0x30 );
907 			SLA( reg, 1, reg = result )
908 		}
909 
910 	// Rotate right
911 
912 	#define RRC( read, write ) {\
913 		int result = read;\
914 		flags = result & C01;\
915 		result = BYTE( result << 7 ) + (result >> 1);\
916 		flags += SZ28P( result );\
917 		write;\
918 		goto loop;\
919 	}
920 
921 		case 0x0E: // RRC (HL)
922 			s_time += 7;
923 			data = r.w.hl;
924 		rrc_data_addr:
RRC(READ_MEM (data),WRITE_MEM (data,result))925 			RRC( READ_MEM( data ), WRITE_MEM( data, result ) )
926 
927 		CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r
928 			byte& reg = R8( data, 0x08 );
929 			RRC( reg, reg = result )
930 		}
931 
932 	#define RR( read, write ) {\
933 		int result = read;\
934 		int temp = result & C01;\
935 		result = BYTE( flags << 7 ) + (result >> 1);\
936 		flags = SZ28P( result ) + temp;\
937 		write;\
938 		goto loop;\
939 	}
940 
941 		case 0x1E: // RR (HL)
942 			s_time += 7;
943 			data = r.w.hl;
944 		rr_data_addr:
RR(READ_MEM (data),WRITE_MEM (data,result))945 			RR( READ_MEM( data ), WRITE_MEM( data, result ) )
946 
947 		CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r
948 			byte& reg = R8( data, 0x18 );
949 			RR( reg, reg = result )
950 		}
951 
952 	#define SRA( read, write ) {\
953 		int result = read;\
954 		flags = result & C01;\
955 		result = (result & 0x80) + (result >> 1);\
956 		flags += SZ28P( result );\
957 		write;\
958 		goto loop;\
959 	}
960 
961 		case 0x2E: // SRA (HL)
962 			data = r.w.hl;
963 			s_time += 7;
964 		sra_data_addr:
SRA(READ_MEM (data),WRITE_MEM (data,result))965 			SRA( READ_MEM( data ), WRITE_MEM( data, result ) )
966 
967 		CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r
968 			byte& reg = R8( data, 0x28 );
969 			SRA( reg, reg = result )
970 		}
971 
972 	#define SRL( read, write ) {\
973 		int result = read;\
974 		flags = result & C01;\
975 		result >>= 1;\
976 		flags += SZ28P( result );\
977 		write;\
978 		goto loop;\
979 	}
980 
981 		case 0x3E: // SRL (HL)
982 			s_time += 7;
983 			data = r.w.hl;
984 		srl_data_addr:
SRL(READ_MEM (data),WRITE_MEM (data,result))985 			SRL( READ_MEM( data ), WRITE_MEM( data, result ) )
986 
987 		CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r
988 			byte& reg = R8( data, 0x38 );
989 			SRL( reg, reg = result )
990 		}
991 
992 	// BIT
993 		{
994 			int temp;
995 		CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL)
996 			s_time += 4;
997 			temp = READ_MEM( r.w.hl );
998 			flags &= C01;
999 			goto bit_temp;
1000 		CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r
1001 		CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r
1002 		CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r
1003 		CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r
1004 		CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r
1005 		CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r
1006 		CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r
1007 		CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r
1008 			temp = R8( data & 7, 0 );
1009 			flags = (flags & C01) + (temp & (F20 | F08));
1010 		bit_temp:
1011 			temp = temp & (1 << (data >> 3 & 7));
1012 			flags += (temp & S80) + H10;
1013 			flags += (unsigned) --temp >> 8 & (Z40 | P04);
1014 			goto loop;
1015 		}
1016 
1017 	// SET/RES
1018 		CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL)
CASE8(C6,CE,D6,DE,E6,EE,F6,FE)1019 		CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL)
1020 			s_time += 7;
1021 			int temp = READ_MEM( r.w.hl );
1022 			int bit = 1 << (data >> 3 & 7);
1023 			temp |= bit; // SET
1024 			if ( !(data & 0x40) )
1025 				temp ^= bit; // RES
1026 			WRITE_MEM( r.w.hl, temp );
1027 			goto loop;
1028 		}
1029 
1030 		CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r
1031 		CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r
1032 		CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r
1033 		CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r
1034 		CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r
1035 		CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r
1036 		CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r
1037 		CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r
1038 			R8( data & 7, 0 ) |= 1 << (data >> 3 & 7);
1039 			goto loop;
1040 
1041 		CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r
1042 		CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r
1043 		CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r
1044 		CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r
1045 		CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r
1046 		CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r
1047 		CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r
1048 		CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r
1049 			R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7));
1050 			goto loop;
1051 		}
1052 		assert( false );
1053 	}
1054 
1055 #undef GET_ADDR
1056 #define GET_ADDR()  GET_LE16( &INSTR( 1, pc ) )
1057 
1058 //////////////////////////////////////// ED prefix
1059 	{
1060 	case 0xED:
1061 		pc++;
1062 		s_time += (clock_table + 256) [data] >> 4;
1063 		switch ( data )
1064 		{
1065 		{
1066 			int temp;
1067 		case 0x72: // SBC HL,SP
1068 		case 0x7A: // ADC HL,SP
1069 			temp = sp;
1070 			if ( 0 )
1071 		case 0x42: // SBC HL,BC
1072 		case 0x52: // SBC HL,DE
1073 		case 0x62: // SBC HL,HL
1074 		case 0x4A: // ADC HL,BC
1075 		case 0x5A: // ADC HL,DE
1076 		case 0x6A: // ADC HL,HL
1077 				temp = R16( data >> 3 & 6, 1, 0 );
1078 			int sum = temp + (flags & C01);
1079 			flags = ~data >> 2 & N02;
1080 			if ( flags )
1081 				sum = -sum;
1082 			sum += r.w.hl;
1083 			temp ^= r.w.hl;
1084 			temp ^= sum;
1085 			flags +=(sum >> 16 & C01) +
1086 					(temp >> 8 & H10) +
1087 					(sum >> 8 & (S80 | F20 | F08)) +
1088 					((temp + 0x8000) >> 14 & V04);
1089 			r.w.hl = sum;
1090 			if ( WORD( sum ) )
1091 				goto loop;
1092 			flags += Z40;
1093 			goto loop;
1094 		}
1095 
1096 		CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C)
1097 			int temp = IN_PORT( r.w.bc );
1098 			R8( data >> 3, 8 ) = temp;
1099 			flags = (flags & C01) + SZ28P( temp );
1100 			goto loop;
1101 		}
1102 
1103 		case 0x71: // OUT (C),0
1104 			r.b.flags = 0;
1105 		CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r
1106 			OUT_PORT( r.w.bc, R8( data >> 3, 8 ) );
1107 			goto loop;
1108 
1109 		{
1110 			int temp;
1111 		case 0x73: // LD (ADDR),SP
1112 			temp = sp;
1113 			if ( 0 )
1114 		case 0x43: // LD (ADDR),BC
1115 		case 0x53: // LD (ADDR),DE
1116 				temp = R16( data, 4, 0x43 );
1117 			int addr = GET_ADDR();
1118 			pc += 2;
1119 			WRITE_WORD( addr, temp );
1120 			goto loop;
1121 		}
1122 
1123 		case 0x4B: // LD BC,(ADDR)
1124 		case 0x5B:{// LD DE,(ADDR)
1125 			int addr = GET_ADDR();
1126 			pc += 2;
1127 			R16( data, 4, 0x4B ) = READ_WORD( addr );
1128 			goto loop;
1129 		}
1130 
1131 		case 0x7B:{// LD SP,(ADDR)
1132 			int addr = GET_ADDR();
1133 			pc += 2;
1134 			sp = READ_WORD( addr );
1135 			goto loop;
1136 		}
1137 
1138 		case 0x67:{// RRD
1139 			int temp = READ_MEM( r.w.hl );
1140 			WRITE_MEM( r.w.hl, ((r.b.a << 4) + (temp >> 4)) );
1141 			temp = (r.b.a & 0xF0) + (temp & 0x0F);
1142 			flags = (flags & C01) + SZ28P( temp );
1143 			r.b.a = temp;
1144 			goto loop;
1145 		}
1146 
1147 		case 0x6F:{// RLD
1148 			int temp = READ_MEM( r.w.hl );
1149 			WRITE_MEM( r.w.hl, ((temp << 4) + (r.b.a & 0x0F)) );
1150 			temp = (r.b.a & 0xF0) + (temp >> 4);
1151 			flags = (flags & C01) + SZ28P( temp );
1152 			r.b.a = temp;
1153 			goto loop;
1154 		}
1155 
1156 		CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG
1157 			opcode = 0x10; // flag to do SBC instead of ADC
1158 			flags &= ~C01;
1159 			data = r.b.a;
1160 			r.b.a = 0;
1161 			goto adc_data;
1162 
1163 		{
1164 			int inc;
1165 		case 0xA9: // CPD
1166 		case 0xB9: // CPDR
1167 			inc = -1;
1168 			if ( 0 )
1169 		case 0xA1: // CPI
1170 		case 0xB1: // CPIR
1171 				inc = +1;
1172 			int addr = r.w.hl;
1173 			r.w.hl = addr + inc;
1174 			int temp = READ_MEM( addr );
1175 
1176 			int result = r.b.a - temp;
1177 			flags = (flags & C01) + N02 +
1178 					((((temp ^ r.b.a) & H10) ^ result) & (S80 | H10));
1179 
1180 			if ( !BYTE( result ) )
1181 				flags += Z40;
1182 			result -= (flags & H10) >> 4;
1183 			flags += result & F08;
1184 			flags += result << 4 & F20;
1185 			if ( !--r.w.bc )
1186 				goto loop;
1187 
1188 			flags += V04;
1189 			if ( flags & Z40 || data < 0xB0 )
1190 				goto loop;
1191 
1192 			pc -= 2;
1193 			s_time += 5;
1194 			goto loop;
1195 		}
1196 
1197 		{
1198 			int inc;
1199 		case 0xA8: // LDD
1200 		case 0xB8: // LDDR
1201 			inc = -1;
1202 			if ( 0 )
1203 		case 0xA0: // LDI
1204 		case 0xB0: // LDIR
1205 				inc = +1;
1206 			int addr = r.w.hl;
1207 			r.w.hl = addr + inc;
1208 			int temp = READ_MEM( addr );
1209 
1210 			addr = r.w.de;
1211 			r.w.de = addr + inc;
1212 			WRITE_MEM( addr, temp );
1213 
1214 			temp += r.b.a;
1215 			flags = (flags & (S80 | Z40 | C01)) +
1216 					(temp & F08) + (temp << 4 & F20);
1217 			if ( !--r.w.bc )
1218 				goto loop;
1219 
1220 			flags += V04;
1221 			if ( data < 0xB0 )
1222 				goto loop;
1223 
1224 			pc -= 2;
1225 			s_time += 5;
1226 			goto loop;
1227 		}
1228 
1229 		{
1230 			int inc;
1231 		case 0xAB: // OUTD
1232 		case 0xBB: // OTDR
1233 			inc = -1;
1234 			if ( 0 )
1235 		case 0xA3: // OUTI
1236 		case 0xB3: // OTIR
1237 				inc = +1;
1238 			int addr = r.w.hl;
1239 			r.w.hl = addr + inc;
1240 			int temp = READ_MEM( addr );
1241 
1242 			int b = --r.b.b;
1243 			flags = (temp >> 6 & N02) + SZ28( b );
1244 			if ( b && data >= 0xB0 )
1245 			{
1246 				pc -= 2;
1247 				s_time += 5;
1248 			}
1249 
1250 			OUT_PORT( r.w.bc, temp );
1251 			goto loop;
1252 		}
1253 
1254 		{
1255 			int inc;
1256 		case 0xAA: // IND
1257 		case 0xBA: // INDR
1258 			inc = -1;
1259 			if ( 0 )
1260 		case 0xA2: // INI
1261 		case 0xB2: // INIR
1262 				inc = +1;
1263 
1264 			int addr = r.w.hl;
1265 			r.w.hl = addr + inc;
1266 
1267 			int temp = IN_PORT( r.w.bc );
1268 
1269 			int b = --r.b.b;
1270 			flags = (temp >> 6 & N02) + SZ28( b );
1271 			if ( b && data >= 0xB0 )
1272 			{
1273 				pc -= 2;
1274 				s_time += 5;
1275 			}
1276 
1277 			WRITE_MEM( addr, temp );
1278 			goto loop;
1279 		}
1280 
1281 		case 0x47: // LD I,A
1282 			R.i = r.b.a;
1283 			goto loop;
1284 
1285 		case 0x4F: // LD R,A
1286 			SET_R( r.b.a );
1287 			dprintf( "LD R,A not supported\n" );
1288 			warning = true;
1289 			goto loop;
1290 
1291 		case 0x57: // LD A,I
1292 			r.b.a = R.i;
1293 			goto ld_ai_common;
1294 
1295 		case 0x5F: // LD A,R
1296 			r.b.a = GET_R();
1297 			dprintf( "LD A,R not supported\n" );
1298 			warning = true;
1299 		ld_ai_common:
1300 			flags = (flags & C01) + SZ28( r.b.a ) + (R.iff2 << 2 & V04);
1301 			goto loop;
1302 
1303 		CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN
1304 			R.iff1 = R.iff2;
1305 			goto ret_taken;
1306 
1307 		case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0
1308 			R.im = 0;
1309 			goto loop;
1310 
1311 		case 0x56: case 0x76: // IM 1
1312 			R.im = 1;
1313 			goto loop;
1314 
1315 		case 0x5E: case 0x7E: // IM 2
1316 			R.im = 2;
1317 			goto loop;
1318 
1319 		default:
1320 			dprintf( "Opcode $ED $%02X not supported\n", data );
1321 			warning = true;
1322 			goto loop;
1323 		}
1324 		assert( false );
1325 	}
1326 
1327 //////////////////////////////////////// DD/FD prefix
1328 	{
1329 	int ixy;
1330 	case 0xDD:
1331 		ixy = ix;
1332 		goto ix_prefix;
1333 	case 0xFD:
1334 		ixy = iy;
1335 	ix_prefix:
1336 		pc++;
1337 		int data2 = READ_CODE( pc );
1338 		s_time += (clock_table + 256) [data] & 0x0F;
1339 		switch ( data )
1340 		{
1341 	// TODO: more efficient way of avoid negative address
1342 	// TODO: avoid using this as argument to READ_MEM() since it is evaluated twice
1343 	#define IXY_DISP( ixy, disp )   WORD( (ixy ) + (disp))
1344 
1345 	#define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in;
1346 
1347 	// ADD/ADC/SUB/SBC
1348 
1349 		case 0x96: // SUB (IXY+disp)
1350 		case 0x86: // ADD (IXY+disp)
1351 			flags &= ~C01;
1352 		case 0x9E: // SBC (IXY+disp)
1353 		case 0x8E: // ADC (IXY+disp)
1354 			pc++;
1355 			opcode = data;
1356 			data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1357 			goto adc_data;
1358 
1359 		case 0x94: // SUB HXY
1360 		case 0x84: // ADD HXY
1361 			flags &= ~C01;
1362 		case 0x9C: // SBC HXY
1363 		case 0x8C: // ADC HXY
1364 			opcode = data;
1365 			data = ixy >> 8;
1366 			goto adc_data;
1367 
1368 		case 0x95: // SUB LXY
1369 		case 0x85: // ADD LXY
1370 			flags &= ~C01;
1371 		case 0x9D: // SBC LXY
1372 		case 0x8D: // ADC LXY
1373 			opcode = data;
1374 			data = BYTE( ixy );
1375 			goto adc_data;
1376 
1377 		{
1378 			int temp;
1379 		case 0x39: // ADD IXY,SP
1380 			temp = sp;
1381 			goto add_ixy_data;
1382 
1383 		case 0x29: // ADD IXY,HL
1384 			temp = ixy;
1385 			goto add_ixy_data;
1386 
1387 		case 0x09: // ADD IXY,BC
1388 		case 0x19: // ADD IXY,DE
1389 			temp = R16( data, 4, 0x09 );
1390 		add_ixy_data: {
1391 			int sum = ixy + temp;
1392 			temp ^= ixy;
1393 			ixy = WORD( sum );
1394 			flags = (flags & (S80 | Z40 | V04)) +
1395 					(sum >> 16) +
1396 					(sum >> 8 & (F20 | F08)) +
1397 					((temp ^ sum) >> 8 & H10);
1398 			goto set_ixy;
1399 		}
1400 		}
1401 
1402 	// AND
1403 		case 0xA6: // AND (IXY+disp)
1404 			pc++;
1405 			data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1406 			goto and_data;
1407 
1408 		case 0xA4: // AND HXY
1409 			data = ixy >> 8;
1410 			goto and_data;
1411 
1412 		case 0xA5: // AND LXY
1413 			data = BYTE( ixy );
1414 			goto and_data;
1415 
1416 	// OR
1417 		case 0xB6: // OR (IXY+disp)
1418 			pc++;
1419 			data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1420 			goto or_data;
1421 
1422 		case 0xB4: // OR HXY
1423 			data = ixy >> 8;
1424 			goto or_data;
1425 
1426 		case 0xB5: // OR LXY
1427 			data = BYTE( ixy );
1428 			goto or_data;
1429 
1430 	// XOR
1431 		case 0xAE: // XOR (IXY+disp)
1432 			pc++;
1433 			data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1434 			goto xor_data;
1435 
1436 		case 0xAC: // XOR HXY
1437 			data = ixy >> 8;
1438 			goto xor_data;
1439 
1440 		case 0xAD: // XOR LXY
1441 			data = BYTE( ixy );
1442 			goto xor_data;
1443 
1444 	// CP
1445 		case 0xBE: // CP (IXY+disp)
1446 			pc++;
1447 			data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) )  );
1448 			goto cp_data;
1449 
1450 		case 0xBC: // CP HXY
1451 			data = ixy >> 8;
1452 			goto cp_data;
1453 
1454 		case 0xBD: // CP LXY
1455 			data = BYTE( ixy );
1456 			goto cp_data;
1457 
1458 	// LD
1459 		CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r
1460 			data = R8( data, 0x70 );
1461 			if ( 0 )
1462 		case 0x36: // LD (IXY+disp),imm
1463 				pc++, data = READ_CODE( pc );
1464 			pc++;
1465 			WRITE_MEM( IXY_DISP( ixy, SBYTE( data2 ) ), data );
1466 			goto loop;
1467 
1468 		CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY
1469 			R8( data >> 3, 8 ) = ixy >> 8;
1470 			goto loop;
1471 
1472 		case 0x64: // LD HXY,HXY
1473 		case 0x6D: // LD LXY,LXY
1474 			goto loop;
1475 
1476 		CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY
1477 			R8( data >> 3, 8 ) = ixy;
1478 			goto loop;
1479 
1480 		CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp)
1481 			pc++;
1482 			R8( data >> 3, 8 ) = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1483 			goto loop;
1484 
1485 		case 0x26: // LD HXY,imm
1486 			pc++;
1487 			goto ld_hxy_data;
1488 
1489 		case 0x65: // LD HXY,LXY
1490 			data2 = BYTE( ixy );
1491 			goto ld_hxy_data;
1492 
1493 		CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r
1494 			data2 = R8( data, 0x60 );
1495 		ld_hxy_data:
1496 			ixy = BYTE( ixy ) + (data2 << 8);
1497 			goto set_ixy;
1498 
1499 		case 0x2E: // LD LXY,imm
1500 			pc++;
1501 			goto ld_lxy_data;
1502 
1503 		case 0x6C: // LD LXY,HXY
1504 			data2 = ixy >> 8;
1505 			goto ld_lxy_data;
1506 
1507 		CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r
1508 			data2 = R8( data, 0x68 );
1509 		ld_lxy_data:
1510 			ixy = (ixy & 0xFF00) + data2;
1511 		set_ixy:
1512 			if ( opcode == 0xDD )
1513 			{
1514 				ix = ixy;
1515 				goto loop;
1516 			}
1517 			iy = ixy;
1518 			goto loop;
1519 
1520 		case 0xF9: // LD SP,IXY
1521 			sp = ixy;
1522 			goto loop;
1523 
1524 		case 0x22:{// LD (ADDR),IXY
1525 			int addr = GET_ADDR();
1526 			pc += 2;
1527 			WRITE_WORD( addr, ixy );
1528 			goto loop;
1529 		}
1530 
1531 		case 0x21: // LD IXY,imm
1532 			ixy = GET_ADDR();
1533 			pc += 2;
1534 			goto set_ixy;
1535 
1536 		case 0x2A:{// LD IXY,(addr)
1537 			int addr = GET_ADDR();
1538 			ixy = READ_WORD( addr );
1539 			pc += 2;
1540 			goto set_ixy;
1541 		}
1542 
1543 	// DD/FD CB prefix
1544 		case 0xCB: {
1545 			data = IXY_DISP( ixy, SBYTE( data2 ) );
1546 			pc++;
1547 			data2 = READ_CODE( pc );
1548 			pc++;
1549 			switch ( data2 )
1550 			{
1551 			case 0x06: goto rlc_data_addr; // RLC (IXY)
1552 			case 0x16: goto rl_data_addr;  // RL (IXY)
1553 			case 0x26: goto sla_data_addr; // SLA (IXY)
1554 			case 0x36: goto sll_data_addr; // SLL (IXY)
1555 			case 0x0E: goto rrc_data_addr; // RRC (IXY)
1556 			case 0x1E: goto rr_data_addr;  // RR (IXY)
1557 			case 0x2E: goto sra_data_addr; // SRA (IXY)
1558 			case 0x3E: goto srl_data_addr; // SRL (IXY)
1559 
1560 			CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp)
1561 				int temp = READ_MEM( data );
1562 				temp = temp & (1 << (data2 >> 3 & 7));
1563 				flags = (flags & C01) + H10 + (temp & S80);
1564 				flags += (unsigned) --temp >> 8 & (Z40 | P04);
1565 				goto loop;
1566 			}
1567 
1568 			CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp)
CASE8(C6,CE,D6,DE,E6,EE,F6,FE)1569 			CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp)
1570 				int temp = READ_MEM( data );
1571 				int bit = 1 << (data2 >> 3 & 7);
1572 				temp |= bit; // SET
1573 				if ( !(data2 & 0x40) )
1574 					temp ^= bit; // RES
1575 				WRITE_MEM( data, temp );
1576 				goto loop;
1577 			}
1578 
1579 			default:
1580 				dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 );
1581 				warning = true;
1582 				goto loop;
1583 			}
1584 			assert( false );
1585 		}
1586 
1587 	// INC/DEC
1588 		case 0x23: // INC IXY
1589 			ixy = WORD( ixy + 1 );
1590 			goto set_ixy;
1591 
1592 		case 0x2B: // DEC IXY
1593 			ixy = WORD( ixy - 1 );
1594 			goto set_ixy;
1595 
1596 		case 0x34: // INC (IXY+disp)
1597 			ixy = IXY_DISP( ixy, SBYTE( data2 ) );
1598 			pc++;
1599 			data = READ_MEM( ixy ) + 1;
1600 			WRITE_MEM( ixy, data );
1601 			goto inc_set_flags;
1602 
1603 		case 0x35: // DEC (IXY+disp)
1604 			ixy = IXY_DISP( ixy, SBYTE( data2 ) );
1605 			pc++;
1606 			data = READ_MEM( ixy ) - 1;
1607 			WRITE_MEM( ixy, data );
1608 			goto dec_set_flags;
1609 
1610 		case 0x24: // INC HXY
1611 			ixy = WORD( ixy + 0x100 );
1612 			data = ixy >> 8;
1613 			goto inc_xy_common;
1614 
1615 		case 0x2C: // INC LXY
1616 			data = BYTE( ixy + 1 );
1617 			ixy = (ixy & 0xFF00) + data;
1618 		inc_xy_common:
1619 			if ( opcode == 0xDD )
1620 			{
1621 				ix = ixy;
1622 				goto inc_set_flags;
1623 			}
1624 			iy = ixy;
1625 			goto inc_set_flags;
1626 
1627 		case 0x25: // DEC HXY
1628 			ixy = WORD( ixy - 0x100 );
1629 			data = ixy >> 8;
1630 			goto dec_xy_common;
1631 
1632 		case 0x2D: // DEC LXY
1633 			data = BYTE( ixy - 1 );
1634 			ixy = (ixy & 0xFF00) + data;
1635 		dec_xy_common:
1636 			if ( opcode == 0xDD )
1637 			{
1638 				ix = ixy;
1639 				goto dec_set_flags;
1640 			}
1641 			iy = ixy;
1642 			goto dec_set_flags;
1643 
1644 	// PUSH/POP
1645 		case 0xE5: // PUSH IXY
1646 			data = ixy;
1647 			goto push_data;
1648 
1649 		case 0xE1:{// POP IXY
1650 			ixy = READ_WORD( sp );
1651 			sp = WORD( sp + 2 );
1652 			goto set_ixy;
1653 		}
1654 
1655 	// Misc
1656 
1657 		case 0xE9: // JP (IXY)
1658 			pc = ixy;
1659 			goto loop;
1660 
1661 		case 0xE3:{// EX (SP),IXY
1662 			int temp = READ_WORD( sp );
1663 			WRITE_WORD( sp, ixy );
1664 			ixy = temp;
1665 			goto set_ixy;
1666 		}
1667 
1668 		default:
1669 			dprintf( "Unnecessary DD/FD prefix encountered\n" );
1670 			warning = true;
1671 			pc--;
1672 			goto loop;
1673 		}
1674 		assert( false );
1675 	}
1676 
1677 	}
1678 	dprintf( "Unhandled main opcode: $%02X\n", opcode );
1679 	assert( false );
1680 
1681 #ifdef IDLE_ADDR
1682 hit_idle_addr:
1683 	s_time -= 11;
1684 	goto out_of_time;
1685 #endif
1686 halt:
1687 	s_time &= 3; // increment by multiple of 4
1688 out_of_time:
1689 	pc--;
1690 
1691 	r.b.flags = flags;
1692 	R.ix     = ix;
1693 	R.iy     = iy;
1694 	R.sp     = sp;
1695 	R.pc     = pc;
1696 	R.b      = r.b;
1697 
1698 	CPU.cpu_state_.base = s.base;
1699 	CPU.cpu_state_.time = s_time;
1700 	CPU.cpu_state = &CPU.cpu_state_;
1701 }
1702