1 // Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
2 
3 /*
4 Last validated with zexall 2006.11.14 2:19 PM
5 * Doesn't implement the R register or immediate interrupt after EI.
6 * Address wrap-around isn't completely correct, but is prevented from crashing emulator.
7 */
8 
9 #include "Kss_Cpu.h"
10 
11 #include "blargg_endian.h"
12 #include <string.h>
13 
14 //#include "z80_cpu_log.h"
15 
16 /* Copyright (C) 2006 Shay Green. This module is free software; you
17 can redistribute it and/or modify it under the terms of the GNU Lesser
18 General Public License as published by the Free Software Foundation; either
19 version 2.1 of the License, or (at your option) any later version. This
20 module is distributed in the hope that it will be useful, but WITHOUT ANY
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
23 details. You should have received a copy of the GNU Lesser General Public
24 License along with this module; if not, write to the Free Software Foundation,
25 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
26 
27 #define SYNC_TIME()     (void) (s.time = s_time)
Hes_Emu()28 #define RELOAD_TIME()   (void) (s_time = s.time)
29 
30 // Callbacks to emulator
31 
32 #define CPU_OUT( cpu, addr, data, time )\
33 	kss_cpu_out( this, time, addr, data )
34 
35 #define CPU_IN( cpu, addr, time )\
36 	kss_cpu_in( this, time, addr )
37 
38 #define CPU_WRITE( cpu, addr, data, time )\
39 	(SYNC_TIME(), kss_cpu_write( this, addr, data ))
40 
41 #include "blargg_source.h"
42 
43 // flags, named with hex value for clarity
44 int const S80 = 0x80;
45 int const Z40 = 0x40;
46 int const F20 = 0x20;
~Hes_Emu()47 int const H10 = 0x10;
48 int const F08 = 0x08;
unload()49 int const V04 = 0x04;
50 int const P04 = 0x04;
51 int const N02 = 0x02;
52 int const C01 = 0x01;
53 
54 #define SZ28P( n )  szpc [n]
55 #define SZ28PC( n ) szpc [n]
56 #define SZ28C( n )  (szpc [n] & ~P04)
copy_field(byte const * in,char * out)57 #define SZ28( n )   SZ28C( n )
58 
59 #define SET_R( n )  (void) (r.r = n)
60 #define GET_R()     (r.r)
61 
62 Kss_Cpu::Kss_Cpu()
63 {
64 	state = &state_;
65 
66 	for ( int i = 0x100; --i >= 0; )
67 	{
68 		int even = 1;
69 		for ( int p = i; p; p >>= 1 )
70 			even ^= p;
71 		int n = (i & (S80 | F20 | F08)) | ((even & 1) * P04);
72 		szpc [i] = n;
73 		szpc [i + 0x100] = n | C01;
74 	}
75 	szpc [0x000] |= Z40;
76 	szpc [0x100] |= Z40;
77 }
78 
79 inline void Kss_Cpu::set_page( int i, void* write, void const* read )
80 {
81 	blargg_long offset = KSS_CPU_PAGE_OFFSET( i * (blargg_long) page_size );
82 	state->write [i] = (byte      *) write - offset;
copy_hes_fields(byte const * in,track_info_t * out)83 	state->read  [i] = (byte const*) read  - offset;
84 }
85 
86 void Kss_Cpu::reset( void* unmapped_write, void const* unmapped_read )
87 {
88 	check( state == &state_ );
89 	state = &state_;
90 	state_.time = 0;
91 	state_.base = 0;
92 	end_time_   = 0;
track_info_(track_info_t * out,int) const93 
94 	for ( int i = 0; i < page_count + 1; i++ )
95 		set_page( i, unmapped_write, unmapped_read );
96 
97 	memset( &r, 0, sizeof r );
98 }
check_hes_header(void const * header)99 
100 void Kss_Cpu::map_mem( unsigned addr, blargg_ulong size, void* write, void const* read )
101 {
102 	// address range must begin and end on page boundaries
103 	require( addr % page_size == 0 );
104 	require( size % page_size == 0 );
105 
106 	unsigned first_page = addr / page_size;
107 	for ( unsigned i = size / page_size; i--; )
108 	{
109 		blargg_long offset = i * (blargg_long) page_size;
110 		set_page( first_page + i, (byte*) write + offset, (byte const*) read + offset );
111 	}
112 }
113 
Hes_FileHes_File114 #define TIME                        (s_time + s.base)
115 #define RW_MEM( addr, rw )          (s.rw [(addr) >> page_shift] [KSS_CPU_PAGE_OFFSET( addr )])
116 #define READ_PROG( addr )           RW_MEM( addr, read )
117 #define READ( addr )                READ_PROG( addr )
118 //#define WRITE( addr, data )       (void) (RW_MEM( addr, write ) = data)
119 #define WRITE( addr, data )         CPU_WRITE( this, addr, data, TIME )
120 #define READ_WORD( addr )           GET_LE16( &READ( addr ) )
121 #define WRITE_WORD( addr, data )    SET_LE16( &RW_MEM( addr, write ), data )
122 #define IN( addr )                  CPU_IN( this, addr, TIME )
123 #define OUT( addr, data )           CPU_OUT( this, addr, data, TIME )
124 
125 #if BLARGG_BIG_ENDIAN
126 	#define R8( n, offset ) ((r8_ - offset) [n])
127 #elif BLARGG_LITTLE_ENDIAN
128 	#define R8( n, offset ) ((r8_ - offset) [(n) ^ 1])
129 #else
130 	#error "Byte order of CPU must be known"
131 #endif
132 
133 //#define R16( n, shift, offset )   (r16_ [((n) >> shift) - (offset >> shift)])
134 
135 // help compiler see that it can just adjust stack offset, saving an extra instruction
136 #define R16( n, shift, offset )\
137 	(*(uint16_t*) ((char*) r16_ - (offset >> (shift - 1)) + ((n) >> (shift - 1))))
138 
139 #define CASE5( a, b, c, d, e          ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e
140 #define CASE6( a, b, c, d, e, f       ) CASE5( a, b, c, d, e       ): case 0x##f
141 #define CASE7( a, b, c, d, e, f, g    ) CASE6( a, b, c, d, e, f    ): case 0x##g
142 #define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h
143 
144 // high four bits are $ED time - 8, low four bits are $DD/$FD time - 8
145 static byte const ed_dd_timing [0x100] = {
146 //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
147 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
148 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
149 0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00,
150 0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
151 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,
152 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,
153 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,
154 0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00,
155 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,
156 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,
157 0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,
158 0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,
159 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,
160 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
161 0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
162 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
163 };
164 
165 bool Kss_Cpu::run( cpu_time_t end_time )
166 {
167 	set_end_time( end_time );
168 	state_t s = this->state_;
169 	this->state = &s;
170 	bool warning = false;
171 
172 	union {
173 		regs_t rg;
174 		pairs_t rp;
175 		uint8_t r8_ [8]; // indexed
176 		uint16_t r16_ [4];
177 	};
178 	rg = this->r.b;
179 
180 	cpu_time_t s_time = s.time;
181 	uint_fast32_t pc = r.pc;
182 	uint_fast32_t sp = r.sp;
183 	uint_fast32_t ix = r.ix; // TODO: keep in memory for direct access?
184 	uint_fast32_t iy = r.iy;
185 	int flags = r.b.flags;
186 
187 	goto loop;
188 jr_not_taken:
189 	s_time -= 5;
190 	goto loop;
update_eq(blip_eq_t const & eq)191 call_not_taken:
192 	s_time -= 7;
193 jp_not_taken:
194 	pc += 2;
195 loop:
set_voice(int i,Blip_Buffer * center,Blip_Buffer * left,Blip_Buffer * right)196 
197 	check( (unsigned long) pc < 0x10000 );
198 	check( (unsigned long) sp < 0x10000 );
199 	check( (unsigned) flags < 0x100 );
200 	check( (unsigned) ix < 0x10000 );
201 	check( (unsigned) iy < 0x10000 );
202 
recalc_timer_load()203 	uint8_t const* instr = s.read [pc >> page_shift];
204 #define GET_ADDR()  GET_LE16( instr )
205 
206 	uint_fast8_t opcode;
207 
set_tempo_(double t)208 	// TODO: eliminate this special case
209 	#if BLARGG_NONPORTABLE
210 		opcode = instr [pc];
211 		pc++;
212 		instr += pc;
213 	#else
214 		instr += KSS_CPU_PAGE_OFFSET( pc );
start_track_(int track)215 		opcode = *instr++;
216 		pc++;
217 	#endif
218 
219 	static byte const base_timing [0x100] = {
220 	//   0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
221 		 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0
222 		13,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1
223 		12,10,16, 6, 4, 4, 7, 4,12,11,16, 6, 4, 4, 7, 4, // 2
224 		12,10,13, 6,11,11,10, 4,12,11,13, 6, 4, 4, 7, 4, // 3
225 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4
226 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5
227 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6
228 		 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7
229 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8
230 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9
231 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A
232 		 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B
233 		11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C
234 		11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D
235 		11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E
236 		11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F
237 	};
238 
239 	uint_fast16_t data;
240 	data = base_timing [opcode];
241 	if ( (s_time += data) >= 0 )
242 		goto possibly_out_of_time;
243 almost_out_of_time:
244 
245 	data = READ_PROG( pc );
246 
247 	#ifdef Z80_CPU_LOG_H
248 		//log_opcode( opcode, READ_PROG( pc ) );
249 		z80_log_regs( rg.a, rp.bc, rp.de, rp.hl, sp, ix, iy );
250 		z80_cpu_log( "new", pc - 1, opcode, READ_PROG( pc ),
251 				READ_PROG( pc + 1 ), READ_PROG( pc + 2 ) );
252 	#endif
253 
254 	switch ( opcode )
255 	{
256 possibly_out_of_time:
cpu_write_vdp(int addr,int data)257 		if ( s_time < (int) data )
258 			goto almost_out_of_time;
259 		s_time -= data;
260 		goto out_of_time;
261 
262 // Common
263 
264 	case 0x00: // NOP
265 	CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc.
266 		goto loop;
267 
268 	case 0x08:{// EX AF,AF'
269 		int temp = r.alt.b.a;
270 		r.alt.b.a = rg.a;
271 		rg.a = temp;
272 
273 		temp = r.alt.b.flags;
274 		r.alt.b.flags = flags;
275 		flags = temp;
276 		goto loop;
277 	}
278 
279 	case 0xD3: // OUT (imm),A
280 		pc++;
281 		OUT( data + rg.a * 0x100, rg.a );
282 		goto loop;
283 
284 	case 0x2E: // LD L,imm
285 		pc++;
cpu_write_(hes_addr_t addr,int data)286 		rg.l = data;
287 		goto loop;
288 
289 	case 0x3E: // LD A,imm
290 		pc++;
291 		rg.a = data;
292 		goto loop;
293 
294 	case 0x3A:{// LD A,(addr)
295 		uint_fast16_t addr = GET_ADDR();
296 		pc += 2;
297 		rg.a = READ( addr );
298 		goto loop;
299 	}
300 
301 // Conditional
302 
303 #define ZERO    (flags & Z40)
304 #define CARRY   (flags & C01)
305 #define EVEN    (flags & P04)
306 #define MINUS   (flags & S80)
307 
308 // JR
309 // TODO: more efficient way to handle negative branch that wraps PC around
310 #define JR( cond ) {\
311 	int offset = (int8_t) data;\
312 	pc++;\
313 	if ( !(cond) )\
314 		goto jr_not_taken;\
315 	pc = uint16_t (pc + offset);\
316 	goto loop;\
317 }
318 
319 	case 0x20: JR( !ZERO  ) // JR NZ,disp
320 	case 0x28: JR(  ZERO  ) // JR Z,disp
321 	case 0x30: JR( !CARRY ) // JR NC,disp
322 	case 0x38: JR(  CARRY ) // JR C,disp
323 	case 0x18: JR(  true  ) // JR disp
324 
325 	case 0x10:{// DJNZ disp
326 		int temp = rg.b - 1;
327 		rg.b = temp;
328 		JR( temp )
329 	}
330 
331 // JP
332 #define JP( cond )  if ( !(cond) ) goto jp_not_taken; pc = GET_ADDR(); goto loop;
333 
334 	case 0xC2: JP( !ZERO  ) // JP NZ,addr
335 	case 0xCA: JP(  ZERO  ) // JP Z,addr
336 	case 0xD2: JP( !CARRY ) // JP NC,addr
337 	case 0xDA: JP(  CARRY ) // JP C,addr
338 	case 0xE2: JP( !EVEN  ) // JP PO,addr
339 	case 0xEA: JP(  EVEN  ) // JP PE,addr
340 	case 0xF2: JP( !MINUS ) // JP P,addr
341 	case 0xFA: JP(  MINUS ) // JP M,addr
342 
343 	case 0xC3: // JP addr
344 		pc = GET_ADDR();
345 		goto loop;
346 
347 	case 0xE9: // JP HL
348 		pc = rp.hl;
349 		goto loop;
350 
351 // RET
352 #define RET( cond ) if ( cond ) goto ret_taken; s_time -= 6; goto loop;
353 
354 	case 0xC0: RET( !ZERO  ) // RET NZ
cpu_read_(hes_addr_t addr)355 	case 0xC8: RET(  ZERO  ) // RET Z
356 	case 0xD0: RET( !CARRY ) // RET NC
357 	case 0xD8: RET(  CARRY ) // RET C
358 	case 0xE0: RET( !EVEN  ) // RET PO
359 	case 0xE8: RET(  EVEN  ) // RET PE
360 	case 0xF0: RET( !MINUS ) // RET P
361 	case 0xF8: RET(  MINUS ) // RET M
362 
363 	case 0xC9: // RET
364 	ret_taken:
365 		pc = READ_WORD( sp );
366 		sp = uint16_t (sp + 2);
367 		goto loop;
368 
369 // CALL
370 #define CALL( cond ) if ( cond ) goto call_taken; goto call_not_taken;
371 
372 	case 0xC4: CALL( !ZERO  ) // CALL NZ,addr
373 	case 0xCC: CALL(  ZERO  ) // CALL Z,addr
374 	case 0xD4: CALL( !CARRY ) // CALL NC,addr
375 	case 0xDC: CALL(  CARRY ) // CALL C,addr
376 	case 0xE4: CALL( !EVEN  ) // CALL PO,addr
377 	case 0xEC: CALL(  EVEN  ) // CALL PE,addr
378 	case 0xF4: CALL( !MINUS ) // CALL P,addr
379 	case 0xFC: CALL(  MINUS ) // CALL M,addr
380 
381 	case 0xCD:{// CALL addr
382 	call_taken:
383 		uint_fast16_t addr = pc + 2;
384 		pc = GET_ADDR();
385 		sp = uint16_t (sp - 2);
386 		WRITE_WORD( sp, addr );
387 		goto loop;
388 	}
389 
390 	case 0xFF: // RST
391 		if ( pc > idle_addr )
392 			goto hit_idle_addr;
393 	CASE7( C7, CF, D7, DF, E7, EF, F7 ):
394 		data = pc;
395 		pc = opcode & 0x38;
396 		goto push_data;
397 
398 // PUSH/POP
399 	case 0xF5: // PUSH AF
400 		data = rg.a * 0x100u + flags;
401 		goto push_data;
402 
403 	case 0xC5: // PUSH BC
404 	case 0xD5: // PUSH DE
405 	case 0xE5: // PUSH HL
406 		data = R16( opcode, 4, 0xC5 );
407 	push_data:
408 		sp = uint16_t (sp - 2);
409 		WRITE_WORD( sp, data );
run_until(hes_time_t present)410 		goto loop;
411 
412 	case 0xF1: // POP AF
413 		flags = READ( sp );
414 		rg.a = READ( sp + 1 );
415 		sp = uint16_t (sp + 2);
416 		goto loop;
417 
418 	case 0xC1: // POP BC
419 	case 0xD1: // POP DE
420 	case 0xE1: // POP HL
421 		R16( opcode, 4, 0xC1 ) = READ_WORD( sp );
422 		sp = uint16_t (sp + 2);
423 		goto loop;
424 
425 // ADC/ADD/SBC/SUB
426 	case 0x96: // SUB (HL)
427 	case 0x86: // ADD (HL)
irq_changed()428 		flags &= ~C01;
429 	case 0x9E: // SBC (HL)
430 	case 0x8E: // ADC (HL)
431 		data = READ( rp.hl );
432 		goto adc_data;
433 
434 	case 0xD6: // SUB A,imm
435 	case 0xC6: // ADD imm
436 		flags &= ~C01;
437 	case 0xDE: // SBC A,imm
438 	case 0xCE: // ADC imm
439 		pc++;
440 		goto adc_data;
441 
442 	CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r
443 	CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r
444 		flags &= ~C01;
445 	CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r
446 	CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r
447 		data = R8( opcode & 7, 0 );
448 	adc_data: {
449 		int result = data + (flags & C01);
450 		data ^= rg.a;
451 		flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes
452 		if ( flags )
cpu_done()453 			result = -result;
454 		result += rg.a;
455 		data ^= result;
456 		flags |=(data & H10) |
457 				((data - -0x80) >> 6 & V04) |
458 				SZ28C( result & 0x1FF );
459 		rg.a = result;
460 		goto loop;
461 	}
462 
463 // CP
464 	case 0xBE: // CP (HL)
465 		data = READ( rp.hl );
466 		goto cp_data;
467 
468 	case 0xFE: // CP imm
469 		pc++;
470 		goto cp_data;
471 
472 	CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r
473 		data = R8( opcode, 0xB8 );
474 	cp_data: {
475 		int result = rg.a - data;
476 		flags = N02 | (data & (F20 | F08)) | (result >> 8 & C01);
477 		data ^= rg.a;
478 		flags |=(((result ^ rg.a) & data) >> 5 & V04) |
479 				(((data & H10) ^ result) & (S80 | H10));
480 		if ( (uint8_t) result )
481 			goto loop;
482 		flags |= Z40;
483 		goto loop;
484 	}
485 
486 // ADD HL,rp
487 
488 	case 0x39: // ADD HL,SP
489 		data = sp;
490 		goto add_hl_data;
491 
492 	case 0x09: // ADD HL,BC
493 	case 0x19: // ADD HL,DE
494 	case 0x29: // ADD HL,HL
495 		data = R16( opcode, 4, 0x09 );
496 	add_hl_data: {
adjust_time(blargg_long & time,hes_time_t delta)497 		blargg_ulong sum = rp.hl + data;
498 		data ^= rp.hl;
499 		rp.hl = sum;
500 		flags = (flags & (S80 | Z40 | V04)) |
501 				(sum >> 16) |
502 				(sum >> 8 & (F20 | F08)) |
503 				((data ^ sum) >> 8 & H10);
504 		goto loop;
505 	}
506 
run_clocks(blip_time_t & duration_,int)507 	case 0x27:{// DAA
508 		int a = rg.a;
509 		if ( a > 0x99 )
510 			flags |= C01;
511 
512 		int adjust = 0x60 & -(flags & C01);
513 
514 		if ( flags & H10 || (a & 0x0F) > 9 )
515 			adjust |= 0x06;
516 
517 		if ( flags & N02 )
518 			adjust = -adjust;
519 		a += adjust;
520 
521 		flags = (flags & (C01 | N02)) |
522 				((rg.a ^ a) & H10) |
523 				SZ28P( (uint8_t) a );
524 		rg.a = a;
525 		goto loop;
526 	}
527 	/*
528 	case 0x27:{// DAA
529 		// more optimized, but probably not worth the obscurity
530 		int f = (rg.a + (0xFF - 0x99)) >> 8 | flags; // (a > 0x99 ? C01 : 0) | flags
531 		int adjust = 0x60 & -(f & C01); // f & C01 ? 0x60 : 0
532 
533 		if ( (((rg.a + (0x0F - 9)) ^ rg.a) | f) & H10 ) // flags & H10 || (rg.a & 0x0F) > 9
534 			adjust |= 0x06;
535 
536 		if ( f & N02 )
537 			adjust = -adjust;
538 		int a = rg.a + adjust;
539 
540 		flags = (f & (N02 | C01)) | ((rg.a ^ a) & H10) | SZ28P( (uint8_t) a );
541 		rg.a = a;
542 		goto loop;
543 	}
544 	*/
545 
546 // INC/DEC
547 	case 0x34: // INC (HL)
548 		data = READ( rp.hl ) + 1;
549 		WRITE( rp.hl, data );
550 		goto inc_set_flags;
551 
552 	CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r
553 		data = ++R8( opcode >> 3, 0 );
554 	inc_set_flags:
555 		flags = (flags & C01) |
556 				(((data & 0x0F) - 1) & H10) |
557 				SZ28( (uint8_t) data );
558 		if ( data != 0x80 )
559 			goto loop;
560 		flags |= V04;
561 		goto loop;
562 
563 	case 0x35: // DEC (HL)
564 		data = READ( rp.hl ) - 1;
565 		WRITE( rp.hl, data );
566 		goto dec_set_flags;
567 
568 	CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r
569 		data = --R8( opcode >> 3, 0 );
570 	dec_set_flags:
571 		flags = (flags & C01) | N02 |
572 				(((data & 0x0F) + 1) & H10) |
573 				SZ28( (uint8_t) data );
574 		if ( data != 0x7F )
575 			goto loop;
576 		flags |= V04;
577 		goto loop;
578 
579 	case 0x03: // INC BC
580 	case 0x13: // INC DE
581 	case 0x23: // INC HL
582 		R16( opcode, 4, 0x03 )++;
583 		goto loop;
584 
585 	case 0x33: // INC SP
586 		sp = uint16_t (sp + 1);
587 		goto loop;
588 
589 	case 0x0B: // DEC BC
590 	case 0x1B: // DEC DE
591 	case 0x2B: // DEC HL
592 		R16( opcode, 4, 0x0B )--;
593 		goto loop;
594 
595 	case 0x3B: // DEC SP
596 		sp = uint16_t (sp - 1);
597 		goto loop;
598 
599 // AND
600 	case 0xA6: // AND (HL)
601 		data = READ( rp.hl );
602 		goto and_data;
603 
604 	case 0xE6: // AND imm
605 		pc++;
606 		goto and_data;
607 
608 	CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r
609 		data = R8( opcode, 0xA0 );
610 	and_data:
611 		rg.a &= data;
612 		flags = SZ28P( rg.a ) | H10;
613 		goto loop;
614 
615 // OR
616 	case 0xB6: // OR (HL)
617 		data = READ( rp.hl );
618 		goto or_data;
619 
620 	case 0xF6: // OR imm
621 		pc++;
622 		goto or_data;
623 
624 	CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r
625 		data = R8( opcode, 0xB0 );
626 	or_data:
627 		rg.a |= data;
628 		flags = SZ28P( rg.a );
629 		goto loop;
630 
631 // XOR
632 	case 0xAE: // XOR (HL)
633 		data = READ( rp.hl );
634 		goto xor_data;
635 
636 	case 0xEE: // XOR imm
637 		pc++;
638 		goto xor_data;
639 
640 	CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r
641 		data = R8( opcode, 0xA8 );
642 	xor_data:
643 		rg.a ^= data;
644 		flags = SZ28P( rg.a );
645 		goto loop;
646 
647 // LD
648 	CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r
649 		WRITE( rp.hl, R8( opcode, 0x70 ) );
650 		goto loop;
651 
652 	CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r
653 	CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r
654 	CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r
655 	CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r
656 	CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r
657 	CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r
658 	CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r
659 		R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 );
660 		goto loop;
661 
662 	CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm
663 		R8( opcode >> 3, 0 ) = data;
664 		pc++;
665 		goto loop;
666 
667 	case 0x36: // LD (HL),imm
668 		pc++;
669 		WRITE( rp.hl, data );
670 		goto loop;
671 
672 	CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL)
673 		R8( opcode >> 3, 8 ) = READ( rp.hl );
674 		goto loop;
675 
676 	case 0x01: // LD rp,imm
677 	case 0x11:
678 	case 0x21:
679 		R16( opcode, 4, 0x01 ) = GET_ADDR();
680 		pc += 2;
681 		goto loop;
682 
683 	case 0x31: // LD sp,imm
684 		sp = GET_ADDR();
685 		pc += 2;
686 		goto loop;
687 
688 	case 0x2A:{// LD HL,(addr)
689 		uint_fast16_t addr = GET_ADDR();
690 		pc += 2;
691 		rp.hl = READ_WORD( addr );
692 		goto loop;
693 	}
694 
695 	case 0x32:{// LD (addr),A
696 		uint_fast16_t addr = GET_ADDR();
697 		pc += 2;
698 		WRITE( addr, rg.a );
699 		goto loop;
700 	}
701 
702 	case 0x22:{// LD (addr),HL
703 		uint_fast16_t addr = GET_ADDR();
704 		pc += 2;
705 		WRITE_WORD( addr, rp.hl );
706 		goto loop;
707 	}
708 
709 	case 0x02: // LD (BC),A
710 	case 0x12: // LD (DE),A
711 		WRITE( R16( opcode, 4, 0x02 ), rg.a );
712 		goto loop;
713 
714 	case 0x0A: // LD A,(BC)
715 	case 0x1A: // LD A,(DE)
716 		rg.a = READ( R16( opcode, 4, 0x0A ) );
717 		goto loop;
718 
719 	case 0xF9: // LD SP,HL
720 		sp = rp.hl;
721 		goto loop;
722 
723 // Rotate
724 
725 	case 0x07:{// RLCA
726 		uint_fast16_t temp = rg.a;
727 		temp = (temp << 1) | (temp >> 7);
728 		flags = (flags & (S80 | Z40 | P04)) |
729 				(temp & (F20 | F08 | C01));
730 		rg.a = temp;
731 		goto loop;
732 	}
733 
734 	case 0x0F:{// RRCA
735 		uint_fast16_t temp = rg.a;
736 		flags = (flags & (S80 | Z40 | P04)) |
737 				(temp & C01);
738 		temp = (temp << 7) | (temp >> 1);
739 		flags |= temp & (F20 | F08);
740 		rg.a = temp;
741 		goto loop;
742 	}
743 
744 	case 0x17:{// RLA
745 		blargg_ulong temp = (rg.a << 1) | (flags & C01);
746 		flags = (flags & (S80 | Z40 | P04)) |
747 				(temp & (F20 | F08)) |
748 				(temp >> 8);
749 		rg.a = (uint8_t)temp;
750 		goto loop;
751 	}
752 
753 	case 0x1F:{// RRA
754 		uint_fast16_t temp = (flags << 7) | (rg.a >> 1);
755 		flags = (flags & (S80 | Z40 | P04)) |
756 				(temp & (F20 | F08)) |
757 				(rg.a & C01);
758 		rg.a = temp;
759 		goto loop;
760 	}
761 
762 // Misc
763 	case 0x2F:{// CPL
764 		uint_fast16_t temp = ~rg.a;
765 		flags = (flags & (S80 | Z40 | P04 | C01)) |
766 				(temp & (F20 | F08)) |
767 				(H10 | N02);
768 		rg.a = temp;
769 		goto loop;
770 	}
771 
772 	case 0x3F:{// CCF
773 		flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) |
774 				(flags << 4 & H10) |
775 				(rg.a & (F20 | F08));
776 		goto loop;
777 	}
778 
779 	case 0x37: // SCF
780 		flags = (flags & (S80 | Z40 | P04)) | C01 |
781 				(rg.a & (F20 | F08));
782 		goto loop;
783 
784 	case 0xDB: // IN A,(imm)
785 		pc++;
786 		rg.a = IN( data + rg.a * 0x100 );
787 		goto loop;
788 
789 	case 0xE3:{// EX (SP),HL
790 		uint_fast16_t temp = READ_WORD( sp );
791 		WRITE_WORD( sp, rp.hl );
792 		rp.hl = temp;
793 		goto loop;
794 	}
795 
796 	case 0xEB:{// EX DE,HL
797 		uint_fast16_t temp = rp.hl;
798 		rp.hl = rp.de;
799 		rp.de = temp;
800 		goto loop;
801 	}
802 
803 	case 0xD9:{// EXX DE,HL
804 		uint_fast16_t temp = r.alt.w.bc;
805 		r.alt.w.bc = rp.bc;
806 		rp.bc = temp;
807 
808 		temp = r.alt.w.de;
809 		r.alt.w.de = rp.de;
810 		rp.de = temp;
811 
812 		temp = r.alt.w.hl;
813 		r.alt.w.hl = rp.hl;
814 		rp.hl = temp;
815 		goto loop;
816 	}
817 
818 	case 0xF3: // DI
819 		r.iff1 = 0;
820 		r.iff2 = 0;
821 		goto loop;
822 
823 	case 0xFB: // EI
824 		r.iff1 = 1;
825 		r.iff2 = 1;
826 		// TODO: delayed effect
827 		goto loop;
828 
829 	case 0x76: // HALT
830 		goto halt;
831 
832 //////////////////////////////////////// CB prefix
833 	{
834 	case 0xCB:
835 		unsigned data2;
836 		data2 = instr [1];
837 		(void) data2; // TODO is this the same as data in all cases?
838 		pc++;
839 		switch ( data )
840 		{
841 
842 	// Rotate left
843 
844 	#define RLC( read, write ) {\
845 		uint_fast8_t result = read;\
846 		result = uint8_t (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 = rp.hl;
855 		rlc_data_addr:
856 			RLC( READ( data ), WRITE( data, result ) )
857 
858 		CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r
859 			uint8_t& reg = R8( data, 0 );
860 			RLC( reg, reg = result )
861 		}
862 
863 	#define RL( read, write ) {\
864 		uint_fast16_t 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 = rp.hl;
873 		rl_data_addr:
874 			RL( READ( data ), WRITE( data, result ) )
875 
876 		CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r
877 			uint8_t& reg = R8( data, 0x10 );
878 			RL( reg, reg = result )
879 		}
880 
881 	#define SLA( read, add, write ) {\
882 		uint_fast16_t result = (read << 1) | add;\
883 		flags = SZ28PC( result );\
884 		write;\
885 		goto loop;\
886 	}
887 
888 		case 0x26: // SLA (HL)
889 			s_time += 7;
890 			data = rp.hl;
891 		sla_data_addr:
892 			SLA( READ( data ), 0, WRITE( data, result ) )
893 
894 		CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r
895 			uint8_t& reg = R8( data, 0x20 );
896 			SLA( reg, 0, reg = result )
897 		}
898 
899 		case 0x36: // SLL (HL)
900 			s_time += 7;
901 			data = rp.hl;
902 		sll_data_addr:
903 			SLA( READ( data ), 1, WRITE( data, result ) )
904 
905 		CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r
906 			uint8_t& reg = R8( data, 0x30 );
907 			SLA( reg, 1, reg = result )
908 		}
909 
910 	// Rotate right
911 
912 	#define RRC( read, write ) {\
913 		uint_fast8_t result = read;\
914 		flags = result & C01;\
915 		result = uint8_t (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 = rp.hl;
924 		rrc_data_addr:
925 			RRC( READ( data ), WRITE( data, result ) )
926 
927 		CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r
928 			uint8_t& reg = R8( data, 0x08 );
929 			RRC( reg, reg = result )
930 		}
931 
932 	#define RR( read, write ) {\
933 		uint_fast8_t result = read;\
934 		uint_fast8_t temp = result & C01;\
935 		result = uint8_t (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 = rp.hl;
944 		rr_data_addr:
945 			RR( READ( data ), WRITE( data, result ) )
946 
947 		CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r
948 			uint8_t& reg = R8( data, 0x18 );
949 			RR( reg, reg = result )
950 		}
951 
952 	#define SRA( read, write ) {\
953 		uint_fast8_t 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 = rp.hl;
963 			s_time += 7;
964 		sra_data_addr:
965 			SRA( READ( data ), WRITE( data, result ) )
966 
967 		CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r
968 			uint8_t& reg = R8( data, 0x28 );
969 			SRA( reg, reg = result )
970 		}
971 
972 	#define SRL( read, write ) {\
973 		uint_fast8_t 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 = rp.hl;
984 		srl_data_addr:
985 			SRL( READ( data ), WRITE( data, result ) )
986 
987 		CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r
988 			uint8_t& reg = R8( data, 0x38 );
989 			SRL( reg, reg = result )
990 		}
991 
992 	// BIT
993 		{
994 			unsigned temp;
995 		CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL)
996 			s_time += 4;
997 			temp = READ( rp.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 			int masked = temp & 1 << (data >> 3 & 7);
1012 			flags |=(masked & S80) | H10 |
1013 					((masked - 1) >> 8 & (Z40 | P04));
1014 			goto loop;
1015 		}
1016 
1017 	// SET/RES
1018 		CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL)
1019 		CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL)
1020 			s_time += 7;
1021 			int temp = READ( rp.hl );
1022 			int bit = 1 << (data >> 3 & 7);
1023 			temp |= bit; // SET
1024 			if ( !(data & 0x40) )
1025 				temp ^= bit; // RES
1026 			WRITE( rp.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 )
1057 
1058 //////////////////////////////////////// ED prefix
1059 	{
1060 	case 0xED:
1061 		pc++;
1062 		s_time += ed_dd_timing [data] >> 4;
1063 		switch ( data )
1064 		{
1065 		{
1066 			blargg_ulong 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 			blargg_ulong sum = temp + (flags & C01);
1079 			flags = ~data >> 2 & N02;
1080 			if ( flags )
1081 				sum = -sum;
1082 			sum += rp.hl;
1083 			temp ^= rp.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 			rp.hl = sum;
1090 			if ( (uint16_t) 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( rp.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 			rg.flags = 0;
1105 		CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r
1106 			OUT( rp.bc, R8( data >> 3, 8 ) );
1107 			goto loop;
1108 
1109 		{
1110 			unsigned 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 			uint_fast16_t 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 			uint_fast16_t 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 			uint_fast16_t addr = GET_ADDR();
1133 			pc += 2;
1134 			sp = READ_WORD( addr );
1135 			goto loop;
1136 		}
1137 
1138 		case 0x67:{// RRD
1139 			uint_fast8_t temp = READ( rp.hl );
1140 			WRITE( rp.hl, (rg.a << 4) | (temp >> 4) );
1141 			temp = (rg.a & 0xF0) | (temp & 0x0F);
1142 			flags = (flags & C01) | SZ28P( temp );
1143 			rg.a = temp;
1144 			goto loop;
1145 		}
1146 
1147 		case 0x6F:{// RLD
1148 			uint_fast8_t temp = READ( rp.hl );
1149 			WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) );
1150 			temp = (rg.a & 0xF0) | (temp >> 4);
1151 			flags = (flags & C01) | SZ28P( temp );
1152 			rg.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 = rg.a;
1160 			rg.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 			uint_fast16_t addr = rp.hl;
1173 			rp.hl = addr + inc;
1174 			int temp = READ( addr );
1175 
1176 			int result = rg.a - temp;
1177 			flags = (flags & C01) | N02 |
1178 					((((temp ^ rg.a) & H10) ^ result) & (S80 | H10));
1179 
1180 			if ( !(uint8_t) result ) flags |= Z40;
1181 			result -= (flags & H10) >> 4;
1182 			flags |= result & F08;
1183 			flags |= result << 4 & F20;
1184 			if ( !--rp.bc )
1185 				goto loop;
1186 
1187 			flags |= V04;
1188 			if ( flags & Z40 || data < 0xB0 )
1189 				goto loop;
1190 
1191 			pc -= 2;
1192 			s_time += 5;
1193 			goto loop;
1194 		}
1195 
1196 		{
1197 			int inc;
1198 		case 0xA8: // LDD
1199 		case 0xB8: // LDDR
1200 			inc = -1;
1201 			if ( 0 )
1202 		case 0xA0: // LDI
1203 		case 0xB0: // LDIR
1204 				inc = +1;
1205 			uint_fast16_t addr = rp.hl;
1206 			rp.hl = addr + inc;
1207 			int temp = READ( addr );
1208 
1209 			addr = rp.de;
1210 			rp.de = addr + inc;
1211 			WRITE( addr, temp );
1212 
1213 			temp += rg.a;
1214 			flags = (flags & (S80 | Z40 | C01)) |
1215 					(temp & F08) | (temp << 4 & F20);
1216 			if ( !--rp.bc )
1217 				goto loop;
1218 
1219 			flags |= V04;
1220 			if ( data < 0xB0 )
1221 				goto loop;
1222 
1223 			pc -= 2;
1224 			s_time += 5;
1225 			goto loop;
1226 		}
1227 
1228 		{
1229 			int inc;
1230 		case 0xAB: // OUTD
1231 		case 0xBB: // OTDR
1232 			inc = -1;
1233 			if ( 0 )
1234 		case 0xA3: // OUTI
1235 		case 0xB3: // OTIR
1236 				inc = +1;
1237 			uint_fast16_t addr = rp.hl;
1238 			rp.hl = addr + inc;
1239 			int temp = READ( addr );
1240 
1241 			int b = --rg.b;
1242 			flags = (temp >> 6 & N02) | SZ28( b );
1243 			if ( b && data >= 0xB0 )
1244 			{
1245 				pc -= 2;
1246 				s_time += 5;
1247 			}
1248 
1249 			OUT( rp.bc, temp );
1250 			goto loop;
1251 		}
1252 
1253 		{
1254 			int inc;
1255 		case 0xAA: // IND
1256 		case 0xBA: // INDR
1257 			inc = -1;
1258 			if ( 0 )
1259 		case 0xA2: // INI
1260 		case 0xB2: // INIR
1261 				inc = +1;
1262 
1263 			uint_fast16_t addr = rp.hl;
1264 			rp.hl = addr + inc;
1265 
1266 			int temp = IN( rp.bc );
1267 
1268 			int b = --rg.b;
1269 			flags = (temp >> 6 & N02) | SZ28( b );
1270 			if ( b && data >= 0xB0 )
1271 			{
1272 				pc -= 2;
1273 				s_time += 5;
1274 			}
1275 
1276 			WRITE( addr, temp );
1277 			goto loop;
1278 		}
1279 
1280 		case 0x47: // LD I,A
1281 			r.i = rg.a;
1282 			goto loop;
1283 
1284 		case 0x4F: // LD R,A
1285 			SET_R( rg.a );
1286 			debug_printf( "LD R,A not supported\n" );
1287 			warning = true;
1288 			goto loop;
1289 
1290 		case 0x57: // LD A,I
1291 			rg.a = r.i;
1292 			goto ld_ai_common;
1293 
1294 		case 0x5F: // LD A,R
1295 			rg.a = GET_R();
1296 			debug_printf( "LD A,R not supported\n" );
1297 			warning = true;
1298 		ld_ai_common:
1299 			flags = (flags & C01) | SZ28( rg.a ) | (r.iff2 << 2 & V04);
1300 			goto loop;
1301 
1302 		CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN
1303 			r.iff1 = r.iff2;
1304 			goto ret_taken;
1305 
1306 		case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0
1307 			r.im = 0;
1308 			goto loop;
1309 
1310 		case 0x56: case 0x76: // IM 1
1311 			r.im = 1;
1312 			goto loop;
1313 
1314 		case 0x5E: case 0x7E: // IM 2
1315 			r.im = 2;
1316 			goto loop;
1317 
1318 		default:
1319 			debug_printf( "Opcode $ED $%02X not supported\n", data );
1320 			warning = true;
1321 			goto loop;
1322 		}
1323 		assert( false );
1324 	}
1325 
1326 //////////////////////////////////////// DD/FD prefix
1327 	{
1328 	uint_fast16_t ixy;
1329 	case 0xDD:
1330 		ixy = ix;
1331 		goto ix_prefix;
1332 	case 0xFD:
1333 		ixy = iy;
1334 	ix_prefix:
1335 		pc++;
1336 		unsigned data2 = READ_PROG( pc );
1337 		s_time += ed_dd_timing [data] & 0x0F;
1338 		switch ( data )
1339 		{
1340 	// TODO: more efficient way of avoid negative address
1341 	// TODO: avoid using this as argument to READ() since it is evaluated twice
1342 	#define IXY_DISP( ixy, disp )   uint16_t ((ixy) + (disp))
1343 
1344 	#define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in;
1345 
1346 	// ADD/ADC/SUB/SBC
1347 
1348 		case 0x96: // SUB (IXY+disp)
1349 		case 0x86: // ADD (IXY+disp)
1350 			flags &= ~C01;
1351 		case 0x9E: // SBC (IXY+disp)
1352 		case 0x8E: // ADC (IXY+disp)
1353 			pc++;
1354 			opcode = data;
1355 			data = READ( IXY_DISP( ixy, (int8_t) data2 ) );
1356 			goto adc_data;
1357 
1358 		case 0x94: // SUB HXY
1359 		case 0x84: // ADD HXY
1360 			flags &= ~C01;
1361 		case 0x9C: // SBC HXY
1362 		case 0x8C: // ADC HXY
1363 			opcode = data;
1364 			data = ixy >> 8;
1365 			goto adc_data;
1366 
1367 		case 0x95: // SUB LXY
1368 		case 0x85: // ADD LXY
1369 			flags &= ~C01;
1370 		case 0x9D: // SBC LXY
1371 		case 0x8D: // ADC LXY
1372 			opcode = data;
1373 			data = (uint8_t) ixy;
1374 			goto adc_data;
1375 
1376 		{
1377 			unsigned temp;
1378 		case 0x39: // ADD IXY,SP
1379 			temp = sp;
1380 			goto add_ixy_data;
1381 
1382 		case 0x29: // ADD IXY,HL
1383 			temp = ixy;
1384 			goto add_ixy_data;
1385 
1386 		case 0x09: // ADD IXY,BC
1387 		case 0x19: // ADD IXY,DE
1388 			temp = R16( data, 4, 0x09 );
1389 		add_ixy_data: {
1390 			blargg_ulong sum = ixy + temp;
1391 			temp ^= ixy;
1392 			ixy = (uint16_t) sum;
1393 			flags = (flags & (S80 | Z40 | V04)) |
1394 					(sum >> 16) |
1395 					(sum >> 8 & (F20 | F08)) |
1396 					((temp ^ sum) >> 8 & H10);
1397 			goto set_ixy;
1398 		}
1399 		}
1400 
1401 	// AND
1402 		case 0xA6: // AND (IXY+disp)
1403 			pc++;
1404 			data = READ( IXY_DISP( ixy, (int8_t) data2 ) );
1405 			goto and_data;
1406 
1407 		case 0xA4: // AND HXY
1408 			data = ixy >> 8;
1409 			goto and_data;
1410 
1411 		case 0xA5: // AND LXY
1412 			data = (uint8_t) ixy;
1413 			goto and_data;
1414 
1415 	// OR
1416 		case 0xB6: // OR (IXY+disp)
1417 			pc++;
1418 			data = READ( IXY_DISP( ixy, (int8_t) data2 ) );
1419 			goto or_data;
1420 
1421 		case 0xB4: // OR HXY
1422 			data = ixy >> 8;
1423 			goto or_data;
1424 
1425 		case 0xB5: // OR LXY
1426 			data = (uint8_t) ixy;
1427 			goto or_data;
1428 
1429 	// XOR
1430 		case 0xAE: // XOR (IXY+disp)
1431 			pc++;
1432 			data = READ( IXY_DISP( ixy, (int8_t) data2 ) );
1433 			goto xor_data;
1434 
1435 		case 0xAC: // XOR HXY
1436 			data = ixy >> 8;
1437 			goto xor_data;
1438 
1439 		case 0xAD: // XOR LXY
1440 			data = (uint8_t) ixy;
1441 			goto xor_data;
1442 
1443 	// CP
1444 		case 0xBE: // CP (IXY+disp)
1445 			pc++;
1446 			data = READ( IXY_DISP( ixy, (int8_t) data2 )  );
1447 			goto cp_data;
1448 
1449 		case 0xBC: // CP HXY
1450 			data = ixy >> 8;
1451 			goto cp_data;
1452 
1453 		case 0xBD: // CP LXY
1454 			data = (uint8_t) ixy;
1455 			goto cp_data;
1456 
1457 	// LD
1458 		CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r
1459 			data = R8( data, 0x70 );
1460 			if ( 0 )
1461 		case 0x36: // LD (IXY+disp),imm
1462 				pc++, data = READ_PROG( pc );
1463 			pc++;
1464 			WRITE( IXY_DISP( ixy, (int8_t) data2 ), data );
1465 			goto loop;
1466 
1467 		CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY
1468 			R8( data >> 3, 8 ) = ixy >> 8;
1469 			goto loop;
1470 
1471 		case 0x64: // LD HXY,HXY
1472 		case 0x6D: // LD LXY,LXY
1473 			goto loop;
1474 
1475 		CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY
1476 			R8( data >> 3, 8 ) = ixy;
1477 			goto loop;
1478 
1479 		CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp)
1480 			pc++;
1481 			R8( data >> 3, 8 ) = READ( IXY_DISP( ixy, (int8_t) data2 ) );
1482 			goto loop;
1483 
1484 		case 0x26: // LD HXY,imm
1485 			pc++;
1486 			goto ld_hxy_data;
1487 
1488 		case 0x65: // LD HXY,LXY
1489 			data2 = (uint8_t) ixy;
1490 			goto ld_hxy_data;
1491 
1492 		CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r
1493 			data2 = R8( data, 0x60 );
1494 		ld_hxy_data:
1495 			ixy = (uint8_t) ixy | (data2 << 8);
1496 			goto set_ixy;
1497 
1498 		case 0x2E: // LD LXY,imm
1499 			pc++;
1500 			goto ld_lxy_data;
1501 
1502 		case 0x6C: // LD LXY,HXY
1503 			data2 = ixy >> 8;
1504 			goto ld_lxy_data;
1505 
1506 		CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r
1507 			data2 = R8( data, 0x68 );
1508 		ld_lxy_data:
1509 			ixy = (ixy & 0xFF00) | data2;
1510 		set_ixy:
1511 			if ( opcode == 0xDD )
1512 			{
1513 				ix = ixy;
1514 				goto loop;
1515 			}
1516 			iy = ixy;
1517 			goto loop;
1518 
1519 		case 0xF9: // LD SP,IXY
1520 			sp = ixy;
1521 			goto loop;
1522 
1523 		case 0x22:{// LD (ADDR),IXY
1524 			uint_fast16_t addr = GET_ADDR();
1525 			pc += 2;
1526 			WRITE_WORD( addr, ixy );
1527 			goto loop;
1528 		}
1529 
1530 		case 0x21: // LD IXY,imm
1531 			ixy = GET_ADDR();
1532 			pc += 2;
1533 			goto set_ixy;
1534 
1535 		case 0x2A:{// LD IXY,(addr)
1536 			uint_fast16_t addr = GET_ADDR();
1537 			ixy = READ_WORD( addr );
1538 			pc += 2;
1539 			goto set_ixy;
1540 		}
1541 
1542 	// DD/FD CB prefix
1543 		case 0xCB: {
1544 			data = IXY_DISP( ixy, (int8_t) data2 );
1545 			pc++;
1546 			data2 = READ_PROG( pc );
1547 			pc++;
1548 			switch ( data2 )
1549 			{
1550 			case 0x06: goto rlc_data_addr; // RLC (IXY)
1551 			case 0x16: goto rl_data_addr;  // RL (IXY)
1552 			case 0x26: goto sla_data_addr; // SLA (IXY)
1553 			case 0x36: goto sll_data_addr; // SLL (IXY)
1554 			case 0x0E: goto rrc_data_addr; // RRC (IXY)
1555 			case 0x1E: goto rr_data_addr;  // RR (IXY)
1556 			case 0x2E: goto sra_data_addr; // SRA (IXY)
1557 			case 0x3E: goto srl_data_addr; // SRL (IXY)
1558 
1559 			CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp)
1560 				uint_fast8_t temp = READ( data );
1561 				int masked = temp & 1 << (data2 >> 3 & 7);
1562 				flags = (flags & C01) | H10 |
1563 						(masked & S80) |
1564 						((masked - 1) >> 8 & (Z40 | P04));
1565 				goto loop;
1566 			}
1567 
1568 			CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp)
1569 			CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp)
1570 				int temp = READ( data );
1571 				int bit = 1 << (data2 >> 3 & 7);
1572 				temp |= bit; // SET
1573 				if ( !(data2 & 0x40) )
1574 					temp ^= bit; // RES
1575 				WRITE( data, temp );
1576 				goto loop;
1577 			}
1578 
1579 			default:
1580 				debug_printf( "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 = uint16_t (ixy + 1);
1590 			goto set_ixy;
1591 
1592 		case 0x2B: // DEC IXY
1593 			ixy = uint16_t (ixy - 1);
1594 			goto set_ixy;
1595 
1596 		case 0x34: // INC (IXY+disp)
1597 			ixy = IXY_DISP( ixy, (int8_t) data2 );
1598 			pc++;
1599 			data = READ( ixy ) + 1;
1600 			WRITE( ixy, data );
1601 			goto inc_set_flags;
1602 
1603 		case 0x35: // DEC (IXY+disp)
1604 			ixy = IXY_DISP( ixy, (int8_t) data2 );
1605 			pc++;
1606 			data = READ( ixy ) - 1;
1607 			WRITE( ixy, data );
1608 			goto dec_set_flags;
1609 
1610 		case 0x24: // INC HXY
1611 			ixy = uint16_t (ixy + 0x100);
1612 			data = ixy >> 8;
1613 			goto inc_xy_common;
1614 
1615 		case 0x2C: // INC LXY
1616 			data = uint8_t (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 = uint16_t (ixy - 0x100);
1629 			data = ixy >> 8;
1630 			goto dec_xy_common;
1631 
1632 		case 0x2D: // DEC LXY
1633 			data = uint8_t (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 = uint16_t (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 			uint_fast16_t temp = READ_WORD( sp );
1663 			WRITE_WORD( sp, ixy );
1664 			ixy = temp;
1665 			goto set_ixy;
1666 		}
1667 
1668 		default:
1669 			debug_printf( "Unnecessary DD/FD prefix encountered\n" );
1670 			warning = true;
1671 			pc--;
1672 			goto loop;
1673 		}
1674 		assert( false );
1675 	}
1676 
1677 	}
1678 	debug_printf( "Unhandled main opcode: $%02X\n", opcode );
1679 	assert( false );
1680 
1681 hit_idle_addr:
1682 	s_time -= 11;
1683 	goto out_of_time;
1684 halt:
1685 	s_time &= 3; // increment by multiple of 4
1686 out_of_time:
1687 	pc--;
1688 
1689 	s.time = s_time;
1690 	rg.flags = flags;
1691 	r.ix    = ix;
1692 	r.iy    = iy;
1693 	r.sp    = sp;
1694 	r.pc    = pc;
1695 	this->r.b = rg;
1696 	this->state_ = s;
1697 	this->state = &this->state_;
1698 
1699 	return warning;
1700 }
1701