PageRenderTime 143ms CodeModel.GetById 15ms app.highlight 116ms RepoModel.GetById 1ms app.codeStats 0ms

/gme/Kss_Cpu.cpp

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