From 569285794b9112f0134ddad4bb886308ea4a7be6 Mon Sep 17 00:00:00 2001 From: Torne Wuff Date: Sun, 6 Nov 2011 22:44:25 +0000 Subject: Bulk convert all DOS line endings to UNIX. For the git migration we want a nice clean repository with UNIX line endings. git does not use svn:eol-style, we just need the file contents to be sane. Sorry everybody. I know this messes up blame. Scumbag *NIX developer says migrating to git will make line ending issues go away; commits giant change to svn which changes line endings anyway. :) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30924 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/libgme/z80_cpu_run.h | 3392 +++++++++++++++++++------------------- 1 file changed, 1696 insertions(+), 1696 deletions(-) (limited to 'apps/codecs/libgme/z80_cpu_run.h') diff --git a/apps/codecs/libgme/z80_cpu_run.h b/apps/codecs/libgme/z80_cpu_run.h index 18195ac92b..a453487bb0 100644 --- a/apps/codecs/libgme/z80_cpu_run.h +++ b/apps/codecs/libgme/z80_cpu_run.h @@ -1,1696 +1,1696 @@ -// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ - -// Last validated with zexall 2009.12.05. -// Doesn't implement the R register or immediate interrupt after EI. -// Address wrap-around isn't completely correct, but is prevented from crashing emulator. -// 16-bit memory accesses are made directly to mapped memory, instead of using macro. - -#if 0 -/* Define these macros in the source file before #including this file. -- Parameters might be expressions, so they are best evaluated only once, -though they NEVER have side-effects, so multiple evaluation is OK. -- Output parameters might be a multiple-assignment expression like "a=x", -so they must NOT be parenthesized. -- Except where noted, time() and related functions will NOT work -correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and -CACHE_TIME() the normal time changing functions can be used. -- Macros "returning" void may use a {} statement block. */ - - // 0 <= addr <= 0xFFFF + 0x100 - // Optional; default uses whatever was set with map_mem() - int READ_MEM( addr_t ); - void WRITE_MEM( addr_t, int data ); - - // 0 <= port <= 0xFFFF (apparently upper 8 bits are output by hardware) - void OUT_PORT( int port, int data ); - int IN_PORT int port ); - - // Reference to Z80_Cpu object used for emulation - #define CPU cpu - -// The following can be used within macros: - - // Current time - time_t TIME(); - - // Allows use of time functions - void FLUSH_TIME(); - - // Must be used before end of macro if FLUSH_TIME() was used earlier - void CACHE_TIME(); - -// Configuration (optional; commented behavior if defined) - - // Optimizes as if map_mem( 0, 0x10000, FLAT_MEM, FLAT_MEM ) is always in effect - #define FLAT_MEM my_mem_array - - // If RST 7 ($FF) is encountered and PC = IDLE_ADDR, stops execution - #define IDLE_ADDR 0x1234 - - // Expanded just before beginning of code, to help debugger - #define CPU_BEGIN void my_run_cpu() { - -#endif - -/* Copyright (C) 2006-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#ifdef CPU_BEGIN - CPU_BEGIN -#endif - -#define R cpu->r - -// flags, named with hex value for clarity -int const S80 = 0x80; -int const Z40 = 0x40; -int const F20 = 0x20; -int const H10 = 0x10; -int const F08 = 0x08; -int const V04 = 0x04; -int const P04 = 0x04; -int const N02 = 0x02; -int const C01 = 0x01; - -#define SZ28P( n ) cpu->szpc [n] -#define SZ28PC( n ) cpu->szpc [n] -#define SZ28C( n ) (cpu->szpc [n] & ~P04) -#define SZ28( n ) SZ28C( n ) - -#define SET_R( n ) (void) (R.r = n) -#define GET_R() (R.r) - -// Time -#define TIME() (s_time + s.base) -#define FLUSH_TIME() {s.time = s_time;} -#define CACHE_TIME() {s_time = s.time;} - -// Memory -#define RW_MEM( addr, rw ) RW_PAGE( addr, rw ) [RW_OFFSET( addr )] -#define READ_CODE( addr ) RW_MEM( addr, read ) - -#ifdef FLAT_MEM - #define RW_PAGE( addr, rw ) FLAT_MEM - #define RW_OFFSET( addr ) (addr) - #define INSTR( off, addr ) READ_CODE( addr ) -#else - #define RW_PAGE( addr, rw ) s.rw [(unsigned) (addr) >> page_bits] - #define RW_OFFSET( addr ) Z80_CPU_OFFSET( addr ) - #define INSTR( off, addr ) instr [off] -#endif - -#ifndef READ_MEM - #define READ_MEM( addr ) RW_MEM( addr, read ) -#endif - -#ifndef WRITE_MEM - #define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data) -#endif - -#define READ_WORD( addr ) GET_LE16( &RW_MEM( addr, read ) ) -#define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data ) - -// Truncation -#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ -#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ -#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ - -// Misc -#define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e -#define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f -#define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g -#define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h - -#ifdef BLARGG_BIG_ENDIAN - #define R8( n, offset ) ((r.r8_ - offset) [n]) -#elif BLARGG_LITTLE_ENDIAN - #define R8( n, offset ) ((r.r8_ - offset) [(n) ^ 1]) -#else - #error "Byte order of CPU must be known" -#endif - -#define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)]) - -#define EX( x, y ) \ - {\ - int temp = x;\ - x = y;\ - y = temp;\ - } - -#define EXX( name ) \ - EX( R.alt.name, r.name ) - -bool warning = false; -{ - struct cpu_state_t s; - #ifdef FLAT_MEM - s.base = cpu->cpu_state_.base; - #else - s = cpu->cpu_state_; - #endif - cpu->cpu_state = &s; - - - union r_t { - struct regs_t b; - struct pairs_t w; - byte r8_ [8]; // indexed - uint16_t r16_ [4]; - } r; - r.b = R.b; - - cpu_time_t s_time = cpu->cpu_state_.time; - int pc = R.pc; - int sp = R.sp; - int ix = R.ix; // TODO: keep in memory for direct access? - int iy = R.iy; - int flags = R.b.flags; - - //goto loop; // confuses optimizer - s_time += 7; - pc -= 2; - -call_not_taken: - s_time -= 7; -jp_not_taken: - pc += 2; -loop: - - check( (unsigned) pc < 0x10000 + 1 ); // +1 so emulator can catch wrap-around - check( (unsigned) sp < 0x10000 ); - check( (unsigned) flags < 0x100 ); - check( (unsigned) ix < 0x10000 ); - check( (unsigned) iy < 0x10000 ); - - byte const* instr = RW_PAGE( pc, read ); - - int opcode; - - if ( RW_OFFSET( ~0 ) == ~0 ) - { - opcode = instr [RW_OFFSET( pc )]; - pc++; - instr += RW_OFFSET( pc ); - } - else - { - instr += RW_OFFSET( pc ); - opcode = *instr++; - pc++; - } - - static byte const clock_table [256 * 2] = { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0 - 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1 - 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, // 2 - 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, // 3 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6 - 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B - 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C - 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D - 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E - 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F - - // high four bits are $ED time - 8, low four bits are $DD/$FD time - 8 - //0 1 2 3 4 5 6 7 8 9 A B C D E F - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00, - 0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, - 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, - 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, - 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0, - 0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, - 0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00, - 0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, - }; - - if ( s_time >= 0 ) - goto out_of_time; - s_time += clock_table [opcode]; - - #ifdef Z80_CPU_LOG_H - //log_opcode( opcode, READ_CODE( pc ) ); - z80_cpu_log( "log.txt", pc - 1, opcode, READ_CODE( pc ), - READ_CODE( pc + 1 ), READ_CODE( pc + 2 ) ); - z80_log_regs( r.b.a, r.w.bc, r.w.de, r.w.hl, sp, ix, iy ); - #endif - -#define GET_ADDR() GET_LE16( &INSTR( 0, pc ) ) - - int data; - data = INSTR( 0, pc ); - - switch ( opcode ) - { -// Common - - case 0x00: // NOP - CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc. - goto loop; - - case 0x08:{// EX AF,AF' - EXX( b.a ); - EX( R.alt.b.flags, flags ); - goto loop; - } - - case 0xD3: // OUT (imm),A - pc++; - OUT_PORT( (data + r.b.a * 0x100), r.b.a ); - goto loop; - - case 0x2E: // LD L,imm - pc++; - r.b.l = data; - goto loop; - - case 0x3E: // LD A,imm - pc++; - r.b.a = data; - goto loop; - - case 0x3A:{// LD A,(addr) - int addr = GET_ADDR(); - pc += 2; - r.b.a = READ_MEM( addr ); - goto loop; - } - -// Conditional - -#define ZERO (flags & Z40) -#define CARRY (flags & C01) -#define EVEN (flags & P04) -#define MINUS (flags & S80) - -// JR -// TODO: more efficient way to handle negative branch that wraps PC around -#define JR_( cond, clocks ) {\ - pc++;\ - if ( !(cond) )\ - goto loop;\ - int offset = SBYTE( data );\ - pc = WORD( pc + offset );\ - s_time += clocks;\ - goto loop;\ -} - -#define JR( cond ) JR_( cond, 5 ) - - case 0x20: JR( !ZERO ) // JR NZ,disp - case 0x28: JR( ZERO ) // JR Z,disp - case 0x30: JR( !CARRY ) // JR NC,disp - case 0x38: JR( CARRY ) // JR C,disp - case 0x18: JR_( true,0) // JR disp - - case 0x10:{// DJNZ disp - int temp = r.b.b - 1; - r.b.b = temp; - JR( temp ) - } - -// JP -#define JP( cond ) \ - if ( !(cond) )\ - goto jp_not_taken;\ - pc = GET_ADDR();\ - goto loop; - - case 0xC2: JP( !ZERO ) // JP NZ,addr - case 0xCA: JP( ZERO ) // JP Z,addr - case 0xD2: JP( !CARRY ) // JP NC,addr - case 0xDA: JP( CARRY ) // JP C,addr - case 0xE2: JP( !EVEN ) // JP PO,addr - case 0xEA: JP( EVEN ) // JP PE,addr - case 0xF2: JP( !MINUS ) // JP P,addr - case 0xFA: JP( MINUS ) // JP M,addr - - case 0xC3: // JP addr - pc = GET_ADDR(); - goto loop; - - case 0xE9: // JP HL - pc = r.w.hl; - goto loop; - -// RET -#define RET( cond ) \ - if ( cond )\ - goto ret_taken;\ - s_time -= 6;\ - goto loop; - - case 0xC0: RET( !ZERO ) // RET NZ - case 0xC8: RET( ZERO ) // RET Z - case 0xD0: RET( !CARRY ) // RET NC - case 0xD8: RET( CARRY ) // RET C - case 0xE0: RET( !EVEN ) // RET PO - case 0xE8: RET( EVEN ) // RET PE - case 0xF0: RET( !MINUS ) // RET P - case 0xF8: RET( MINUS ) // RET M - - case 0xC9: // RET - ret_taken: - pc = READ_WORD( sp ); - sp = WORD( sp + 2 ); - goto loop; - -// CALL -#define CALL( cond ) \ - if ( cond )\ - goto call_taken;\ - goto call_not_taken; - - case 0xC4: CALL( !ZERO ) // CALL NZ,addr - case 0xCC: CALL( ZERO ) // CALL Z,addr - case 0xD4: CALL( !CARRY ) // CALL NC,addr - case 0xDC: CALL( CARRY ) // CALL C,addr - case 0xE4: CALL( !EVEN ) // CALL PO,addr - case 0xEC: CALL( EVEN ) // CALL PE,addr - case 0xF4: CALL( !MINUS ) // CALL P,addr - case 0xFC: CALL( MINUS ) // CALL M,addr - - case 0xCD:{// CALL addr - call_taken: { - int addr = pc + 2; - pc = GET_ADDR(); - sp = WORD( sp - 2 ); - WRITE_WORD( sp, addr ); - goto loop; - } - } - - case 0xFF: // RST - #ifdef IDLE_ADDR - if ( pc == IDLE_ADDR + 1 ) - goto hit_idle_addr; - #else - if ( pc > 0x10000 ) - { - pc = WORD( pc - 1 ); - s_time -= 11; - goto loop; - } - #endif - CASE7( C7, CF, D7, DF, E7, EF, F7 ): - data = pc; - pc = opcode & 0x38; - #ifdef RST_BASE - pc += RST_BASE; - #endif - goto push_data; - -// PUSH/POP - case 0xF5: // PUSH AF - data = r.b.a * 0x100u + flags; - goto push_data; - - case 0xC5: // PUSH BC - case 0xD5: // PUSH DE - case 0xE5: // PUSH HL - data = R16( opcode, 4, 0xC5 ); - push_data: - sp = WORD( sp - 2 ); - WRITE_WORD( sp, data ); - goto loop; - - case 0xF1: // POP AF - flags = READ_MEM( sp ); - r.b.a = READ_MEM( (sp + 1) ); - sp = WORD( sp + 2 ); - goto loop; - - case 0xC1: // POP BC - case 0xD1: // POP DE - case 0xE1: // POP HL - R16( opcode, 4, 0xC1 ) = READ_WORD( sp ); - sp = WORD( sp + 2 ); - goto loop; - -// ADC/ADD/SBC/SUB - case 0x96: // SUB (HL) - case 0x86: // ADD (HL) - flags &= ~C01; - case 0x9E: // SBC (HL) - case 0x8E: // ADC (HL) - data = READ_MEM( r.w.hl ); - goto adc_data; - - case 0xD6: // SUB A,imm - case 0xC6: // ADD imm - flags &= ~C01; - case 0xDE: // SBC A,imm - case 0xCE: // ADC imm - pc++; - goto adc_data; - - CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r - CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r - flags &= ~C01; - CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r - CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r - data = R8( opcode & 7, 0 ); - adc_data: { - int result = data + (flags & C01); - data ^= r.b.a; - flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes - if ( flags ) - result = -result; - result += r.b.a; - data ^= result; - flags +=(data & H10) + - ((data + 0x80) >> 6 & V04) + - SZ28C( result & 0x1FF ); - r.b.a = result; - goto loop; - } - -// CP - case 0xBE: // CP (HL) - data = READ_MEM( r.w.hl ); - goto cp_data; - - case 0xFE: // CP imm - pc++; - goto cp_data; - - CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r - data = R8( opcode, 0xB8 ); - cp_data: { - int result = r.b.a - data; - flags = N02 + (data & (F20 | F08)) + (result >> 8 & C01); - data ^= r.b.a; - flags +=(((result ^ r.b.a) & data) >> 5 & V04) + - (((data & H10) ^ result) & (S80 | H10)); - if ( BYTE( result ) ) - goto loop; - flags += Z40; - goto loop; - } - -// ADD HL,r.w - - case 0x39: // ADD HL,SP - data = sp; - goto add_hl_data; - - case 0x09: // ADD HL,BC - case 0x19: // ADD HL,DE - case 0x29: // ADD HL,HL - data = R16( opcode, 4, 0x09 ); - add_hl_data: { - int sum = r.w.hl + data; - data ^= r.w.hl; - r.w.hl = sum; - flags = (flags & (S80 | Z40 | V04)) + - (sum >> 16) + - (sum >> 8 & (F20 | F08)) + - ((data ^ sum) >> 8 & H10); - goto loop; - } - - case 0x27:{// DAA - int a = r.b.a; - if ( a > 0x99 ) - flags |= C01; - - int adjust = 0x60 * (flags & C01); - - if ( flags & H10 || (a & 0x0F) > 9 ) - adjust += 0x06; - - if ( flags & N02 ) - adjust = -adjust; - a += adjust; - - flags = (flags & (C01 | N02)) + - ((r.b.a ^ a) & H10) + - SZ28P( BYTE( a ) ); - r.b.a = a; - goto loop; - } - -// INC/DEC - case 0x34: // INC (HL) - data = READ_MEM( r.w.hl ) + 1; - WRITE_MEM( r.w.hl, data ); - goto inc_set_flags; - - CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r - data = ++R8( opcode >> 3, 0 ); - inc_set_flags: - flags = (flags & C01) + - (((data & 0x0F) - 1) & H10) + - SZ28( BYTE( data ) ); - if ( data != 0x80 ) - goto loop; - flags += V04; - goto loop; - - case 0x35: // DEC (HL) - data = READ_MEM( r.w.hl ) - 1; - WRITE_MEM( r.w.hl, data ); - goto dec_set_flags; - - CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r - data = --R8( opcode >> 3, 0 ); - dec_set_flags: - flags = (flags & C01) + N02 + - (((data & 0x0F) + 1) & H10) + - SZ28( BYTE( data ) ); - if ( data != 0x7F ) - goto loop; - flags += V04; - goto loop; - - case 0x03: // INC BC - case 0x13: // INC DE - case 0x23: // INC HL - R16( opcode, 4, 0x03 )++; - goto loop; - - case 0x33: // INC SP - sp = WORD( sp + 1 ); - goto loop; - - case 0x0B: // DEC BC - case 0x1B: // DEC DE - case 0x2B: // DEC HL - R16( opcode, 4, 0x0B )--; - goto loop; - - case 0x3B: // DEC SP - sp = WORD( sp - 1 ); - goto loop; - -// AND - case 0xA6: // AND (HL) - data = READ_MEM( r.w.hl ); - goto and_data; - - case 0xE6: // AND imm - pc++; - goto and_data; - - CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r - data = R8( opcode, 0xA0 ); - and_data: - r.b.a &= data; - flags = SZ28P( r.b.a ) + H10; - goto loop; - -// OR - case 0xB6: // OR (HL) - data = READ_MEM( r.w.hl ); - goto or_data; - - case 0xF6: // OR imm - pc++; - goto or_data; - - CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r - data = R8( opcode, 0xB0 ); - or_data: - r.b.a |= data; - flags = SZ28P( r.b.a ); - goto loop; - -// XOR - case 0xAE: // XOR (HL) - data = READ_MEM( r.w.hl ); - goto xor_data; - - case 0xEE: // XOR imm - pc++; - goto xor_data; - - CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r - data = R8( opcode, 0xA8 ); - xor_data: - r.b.a ^= data; - flags = SZ28P( r.b.a ); - goto loop; - -// LD - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r - WRITE_MEM( r.w.hl, R8( opcode, 0x70 ) ); - goto loop; - - CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r - CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r - CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r - CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r - CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r - CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r - CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r - R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 ); - goto loop; - - CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm - R8( opcode >> 3, 0 ) = data; - pc++; - goto loop; - - case 0x36: // LD (HL),imm - pc++; - WRITE_MEM( r.w.hl, data ); - goto loop; - - CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL) - R8( opcode >> 3, 8 ) = READ_MEM( r.w.hl ); - goto loop; - - case 0x01: // LD r.w,imm - case 0x11: - case 0x21: - R16( opcode, 4, 0x01 ) = GET_ADDR(); - pc += 2; - goto loop; - - case 0x31: // LD sp,imm - sp = GET_ADDR(); - pc += 2; - goto loop; - - case 0x2A:{// LD HL,(addr) - int addr = GET_ADDR(); - pc += 2; - r.w.hl = READ_WORD( addr ); - goto loop; - } - - case 0x32:{// LD (addr),A - int addr = GET_ADDR(); - pc += 2; - WRITE_MEM( addr, r.b.a ); - goto loop; - } - - case 0x22:{// LD (addr),HL - int addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, r.w.hl ); - goto loop; - } - - case 0x02: // LD (BC),A - case 0x12: // LD (DE),A - WRITE_MEM( R16( opcode, 4, 0x02 ), r.b.a ); - goto loop; - - case 0x0A: // LD A,(BC) - case 0x1A: // LD A,(DE) - r.b.a = READ_MEM( R16( opcode, 4, 0x0A ) ); - goto loop; - - case 0xF9: // LD SP,HL - sp = r.w.hl; - goto loop; - -// Rotate - - case 0x07:{// RLCA - int temp = r.b.a; - temp = (temp << 1) + (temp >> 7); - flags = (flags & (S80 | Z40 | P04)) + - (temp & (F20 | F08 | C01)); - r.b.a = temp; - goto loop; - } - - case 0x0F:{// RRCA - int temp = r.b.a; - flags = (flags & (S80 | Z40 | P04)) + - (temp & C01); - temp = (temp << 7) + (temp >> 1); - flags += temp & (F20 | F08); - r.b.a = temp; - goto loop; - } - - case 0x17:{// RLA - int temp = (r.b.a << 1) + (flags & C01); - flags = (flags & (S80 | Z40 | P04)) + - (temp & (F20 | F08)) + - (temp >> 8); - r.b.a = temp; - goto loop; - } - - case 0x1F:{// RRA - int temp = (flags << 7) + (r.b.a >> 1); - flags = (flags & (S80 | Z40 | P04)) + - (temp & (F20 | F08)) + - (r.b.a & C01); - r.b.a = temp; - goto loop; - } - -// Misc - case 0x2F:{// CPL - int temp = ~r.b.a; - flags = (flags & (S80 | Z40 | P04 | C01)) + - (temp & (F20 | F08)) + - (H10 | N02); - r.b.a = temp; - goto loop; - } - - case 0x3F:{// CCF - flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) + - (flags << 4 & H10) + - (r.b.a & (F20 | F08)); - goto loop; - } - - case 0x37: // SCF - flags = ((flags & (S80 | Z40 | P04)) | C01) + - (r.b.a & (F20 | F08)); - goto loop; - - case 0xDB: // IN A,(imm) - pc++; - r.b.a = IN_PORT( (data + r.b.a * 0x100) ); - goto loop; - - case 0xE3:{// EX (SP),HL - int temp = READ_WORD( sp ); - WRITE_WORD( sp, r.w.hl ); - r.w.hl = temp; - goto loop; - } - - case 0xEB: // EX DE,HL - EX( r.w.hl, r.w.de ); - goto loop; - - case 0xD9: // EXX DE,HL - EXX( w.bc ); - EXX( w.de ); - EXX( w.hl ); - goto loop; - - case 0xF3: // DI - R.iff1 = 0; - R.iff2 = 0; - goto loop; - - case 0xFB: // EI - R.iff1 = 1; - R.iff2 = 1; - // TODO: delayed effect - goto loop; - - case 0x76: // HALT - goto halt; - -//////////////////////////////////////// CB prefix - { - case 0xCB: - pc++; - switch ( data ) - { - - // Rotate left - - #define RLC( read, write ) {\ - int result = read;\ - result = BYTE( result << 1 ) + (result >> 7);\ - flags = SZ28P( result ) + (result & C01);\ - write;\ - goto loop;\ - } - - case 0x06: // RLC (HL) - s_time += 7; - data = r.w.hl; - rlc_data_addr: - RLC( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r - byte* reg = &R8( data, 0 ); - RLC( *reg, *reg = result ) - } - - #define RL( read, write ) {\ - int result = (read << 1) + (flags & C01);\ - flags = SZ28PC( result );\ - write;\ - goto loop;\ - } - - case 0x16: // RL (HL) - s_time += 7; - data = r.w.hl; - rl_data_addr: - RL( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r - byte* reg = &R8( data, 0x10 ); - RL( *reg, *reg = result ) - } - - #define SLA( read, low_bit, write ) {\ - int result = (read << 1) + low_bit;\ - flags = SZ28PC( result );\ - write;\ - goto loop;\ - } - - case 0x26: // SLA (HL) - s_time += 7; - data = r.w.hl; - sla_data_addr: - SLA( READ_MEM( data ), 0, WRITE_MEM( data, result ) ) - - CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r - byte* reg = &R8( data, 0x20 ); - SLA( *reg, 0, *reg = result ) - } - - case 0x36: // SLL (HL) - s_time += 7; - data = r.w.hl; - sll_data_addr: - SLA( READ_MEM( data ), 1, WRITE_MEM( data, result ) ) - - CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r - byte* reg = &R8( data, 0x30 ); - SLA( *reg, 1, *reg = result ) - } - - // Rotate right - - #define RRC( read, write ) {\ - int result = read;\ - flags = result & C01;\ - result = BYTE( result << 7 ) + (result >> 1);\ - flags += SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x0E: // RRC (HL) - s_time += 7; - data = r.w.hl; - rrc_data_addr: - RRC( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r - byte* reg = &R8( data, 0x08 ); - RRC( *reg, *reg = result ) - } - - #define RR( read, write ) {\ - int result = read;\ - int temp = result & C01;\ - result = BYTE( flags << 7 ) + (result >> 1);\ - flags = SZ28P( result ) + temp;\ - write;\ - goto loop;\ - } - - case 0x1E: // RR (HL) - s_time += 7; - data = r.w.hl; - rr_data_addr: - RR( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r - byte* reg = &R8( data, 0x18 ); - RR( *reg, *reg = result ) - } - - #define SRA( read, write ) {\ - int result = read;\ - flags = result & C01;\ - result = (result & 0x80) + (result >> 1);\ - flags += SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x2E: // SRA (HL) - data = r.w.hl; - s_time += 7; - sra_data_addr: - SRA( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r - byte* reg = &R8( data, 0x28 ); - SRA( *reg, *reg = result ) - } - - #define SRL( read, write ) {\ - int result = read;\ - flags = result & C01;\ - result >>= 1;\ - flags += SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x3E: // SRL (HL) - s_time += 7; - data = r.w.hl; - srl_data_addr: - SRL( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r - byte* reg = &R8( data, 0x38 ); - SRL( *reg, *reg = result ) - } - - // BIT - { - int temp; - CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL) - s_time += 4; - temp = READ_MEM( r.w.hl ); - flags &= C01; - goto bit_temp; - CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r - CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r - CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r - CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r - CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r - CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r - CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r - temp = R8( data & 7, 0 ); - flags = (flags & C01) + (temp & (F20 | F08)); - bit_temp: - temp = temp & (1 << (data >> 3 & 7)); - flags += (temp & S80) + H10; - flags += (unsigned) --temp >> 8 & (Z40 | P04); - goto loop; - } - - // SET/RES - CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL) - CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL) - s_time += 7; - int temp = READ_MEM( r.w.hl ); - int bit = 1 << (data >> 3 & 7); - temp |= bit; // SET - if ( !(data & 0x40) ) - temp ^= bit; // RES - WRITE_MEM( r.w.hl, temp ); - goto loop; - } - - CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r - CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r - CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r - CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r - CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r - CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r - CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r - CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r - R8( data & 7, 0 ) |= 1 << (data >> 3 & 7); - goto loop; - - CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r - CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r - CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r - CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r - CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r - CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r - CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r - CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r - R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7)); - goto loop; - } - assert( false ); - } - -#undef GET_ADDR -#define GET_ADDR() GET_LE16( &INSTR( 1, pc ) ) - -//////////////////////////////////////// ED prefix - { - case 0xED: - pc++; - s_time += (clock_table + 256) [data] >> 4; - switch ( data ) - { - { - int temp; - case 0x72: // SBC HL,SP - case 0x7A: // ADC HL,SP - temp = sp; - if ( 0 ) - case 0x42: // SBC HL,BC - case 0x52: // SBC HL,DE - case 0x62: // SBC HL,HL - case 0x4A: // ADC HL,BC - case 0x5A: // ADC HL,DE - case 0x6A: // ADC HL,HL - temp = R16( data >> 3 & 6, 1, 0 ); - int sum = temp + (flags & C01); - flags = ~data >> 2 & N02; - if ( flags ) - sum = -sum; - sum += r.w.hl; - temp ^= r.w.hl; - temp ^= sum; - flags +=(sum >> 16 & C01) + - (temp >> 8 & H10) + - (sum >> 8 & (S80 | F20 | F08)) + - ((temp + 0x8000) >> 14 & V04); - r.w.hl = sum; - if ( WORD( sum ) ) - goto loop; - flags += Z40; - goto loop; - } - - CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C) - int temp = IN_PORT( r.w.bc ); - R8( data >> 3, 8 ) = temp; - flags = (flags & C01) + SZ28P( temp ); - goto loop; - } - - case 0x71: // OUT (C),0 - r.b.flags = 0; - CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r - OUT_PORT( r.w.bc, R8( data >> 3, 8 ) ); - goto loop; - - { - int temp; - case 0x73: // LD (ADDR),SP - temp = sp; - if ( 0 ) - case 0x43: // LD (ADDR),BC - case 0x53: // LD (ADDR),DE - temp = R16( data, 4, 0x43 ); - int addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, temp ); - goto loop; - } - - case 0x4B: // LD BC,(ADDR) - case 0x5B:{// LD DE,(ADDR) - int addr = GET_ADDR(); - pc += 2; - R16( data, 4, 0x4B ) = READ_WORD( addr ); - goto loop; - } - - case 0x7B:{// LD SP,(ADDR) - int addr = GET_ADDR(); - pc += 2; - sp = READ_WORD( addr ); - goto loop; - } - - case 0x67:{// RRD - int temp = READ_MEM( r.w.hl ); - WRITE_MEM( r.w.hl, ((r.b.a << 4) + (temp >> 4)) ); - temp = (r.b.a & 0xF0) + (temp & 0x0F); - flags = (flags & C01) + SZ28P( temp ); - r.b.a = temp; - goto loop; - } - - case 0x6F:{// RLD - int temp = READ_MEM( r.w.hl ); - WRITE_MEM( r.w.hl, ((temp << 4) + (r.b.a & 0x0F)) ); - temp = (r.b.a & 0xF0) + (temp >> 4); - flags = (flags & C01) + SZ28P( temp ); - r.b.a = temp; - goto loop; - } - - CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG - opcode = 0x10; // flag to do SBC instead of ADC - flags &= ~C01; - data = r.b.a; - r.b.a = 0; - goto adc_data; - - { - int inc; - case 0xA9: // CPD - case 0xB9: // CPDR - inc = -1; - if ( 0 ) - case 0xA1: // CPI - case 0xB1: // CPIR - inc = +1; - int addr = r.w.hl; - r.w.hl = addr + inc; - int temp = READ_MEM( addr ); - - int result = r.b.a - temp; - flags = (flags & C01) + N02 + - ((((temp ^ r.b.a) & H10) ^ result) & (S80 | H10)); - - if ( !BYTE( result ) ) - flags += Z40; - result -= (flags & H10) >> 4; - flags += result & F08; - flags += result << 4 & F20; - if ( !--r.w.bc ) - goto loop; - - flags += V04; - if ( flags & Z40 || data < 0xB0 ) - goto loop; - - pc -= 2; - s_time += 5; - goto loop; - } - - { - int inc; - case 0xA8: // LDD - case 0xB8: // LDDR - inc = -1; - if ( 0 ) - case 0xA0: // LDI - case 0xB0: // LDIR - inc = +1; - int addr = r.w.hl; - r.w.hl = addr + inc; - int temp = READ_MEM( addr ); - - addr = r.w.de; - r.w.de = addr + inc; - WRITE_MEM( addr, temp ); - - temp += r.b.a; - flags = (flags & (S80 | Z40 | C01)) + - (temp & F08) + (temp << 4 & F20); - if ( !--r.w.bc ) - goto loop; - - flags += V04; - if ( data < 0xB0 ) - goto loop; - - pc -= 2; - s_time += 5; - goto loop; - } - - { - int inc; - case 0xAB: // OUTD - case 0xBB: // OTDR - inc = -1; - if ( 0 ) - case 0xA3: // OUTI - case 0xB3: // OTIR - inc = +1; - int addr = r.w.hl; - r.w.hl = addr + inc; - int temp = READ_MEM( addr ); - - int b = --r.b.b; - flags = (temp >> 6 & N02) + SZ28( b ); - if ( b && data >= 0xB0 ) - { - pc -= 2; - s_time += 5; - } - - OUT_PORT( r.w.bc, temp ); - goto loop; - } - - { - int inc; - case 0xAA: // IND - case 0xBA: // INDR - inc = -1; - if ( 0 ) - case 0xA2: // INI - case 0xB2: // INIR - inc = +1; - - int addr = r.w.hl; - r.w.hl = addr + inc; - - int temp = IN_PORT( r.w.bc ); - - int b = --r.b.b; - flags = (temp >> 6 & N02) + SZ28( b ); - if ( b && data >= 0xB0 ) - { - pc -= 2; - s_time += 5; - } - - WRITE_MEM( addr, temp ); - goto loop; - } - - case 0x47: // LD I,A - R.i = r.b.a; - goto loop; - - case 0x4F: // LD R,A - SET_R( r.b.a ); - dprintf( "LD R,A not supported\n" ); - warning = true; - goto loop; - - case 0x57: // LD A,I - r.b.a = R.i; - goto ld_ai_common; - - case 0x5F: // LD A,R - r.b.a = GET_R(); - dprintf( "LD A,R not supported\n" ); - warning = true; - ld_ai_common: - flags = (flags & C01) + SZ28( r.b.a ) + (R.iff2 << 2 & V04); - goto loop; - - CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN - R.iff1 = R.iff2; - goto ret_taken; - - case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0 - R.im = 0; - goto loop; - - case 0x56: case 0x76: // IM 1 - R.im = 1; - goto loop; - - case 0x5E: case 0x7E: // IM 2 - R.im = 2; - goto loop; - - default: - dprintf( "Opcode $ED $%02X not supported\n", data ); - warning = true; - goto loop; - } - assert( false ); - } - -//////////////////////////////////////// DD/FD prefix - { - int ixy; - case 0xDD: - ixy = ix; - goto ix_prefix; - case 0xFD: - ixy = iy; - ix_prefix: - pc++; - int data2 = READ_CODE( pc ); - s_time += (clock_table + 256) [data] & 0x0F; - switch ( data ) - { - // TODO: more efficient way of avoid negative address - // TODO: avoid using this as argument to READ_MEM() since it is evaluated twice - #define IXY_DISP( ixy, disp ) WORD( (ixy ) + (disp)) - - #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in; - - // ADD/ADC/SUB/SBC - - case 0x96: // SUB (IXY+disp) - case 0x86: // ADD (IXY+disp) - flags &= ~C01; - case 0x9E: // SBC (IXY+disp) - case 0x8E: // ADC (IXY+disp) - pc++; - opcode = data; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto adc_data; - - case 0x94: // SUB HXY - case 0x84: // ADD HXY - flags &= ~C01; - case 0x9C: // SBC HXY - case 0x8C: // ADC HXY - opcode = data; - data = ixy >> 8; - goto adc_data; - - case 0x95: // SUB LXY - case 0x85: // ADD LXY - flags &= ~C01; - case 0x9D: // SBC LXY - case 0x8D: // ADC LXY - opcode = data; - data = BYTE( ixy ); - goto adc_data; - - { - int temp; - case 0x39: // ADD IXY,SP - temp = sp; - goto add_ixy_data; - - case 0x29: // ADD IXY,HL - temp = ixy; - goto add_ixy_data; - - case 0x09: // ADD IXY,BC - case 0x19: // ADD IXY,DE - temp = R16( data, 4, 0x09 ); - add_ixy_data: { - int sum = ixy + temp; - temp ^= ixy; - ixy = WORD( sum ); - flags = (flags & (S80 | Z40 | V04)) + - (sum >> 16) + - (sum >> 8 & (F20 | F08)) + - ((temp ^ sum) >> 8 & H10); - goto set_ixy; - } - } - - // AND - case 0xA6: // AND (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto and_data; - - case 0xA4: // AND HXY - data = ixy >> 8; - goto and_data; - - case 0xA5: // AND LXY - data = BYTE( ixy ); - goto and_data; - - // OR - case 0xB6: // OR (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto or_data; - - case 0xB4: // OR HXY - data = ixy >> 8; - goto or_data; - - case 0xB5: // OR LXY - data = BYTE( ixy ); - goto or_data; - - // XOR - case 0xAE: // XOR (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto xor_data; - - case 0xAC: // XOR HXY - data = ixy >> 8; - goto xor_data; - - case 0xAD: // XOR LXY - data = BYTE( ixy ); - goto xor_data; - - // CP - case 0xBE: // CP (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto cp_data; - - case 0xBC: // CP HXY - data = ixy >> 8; - goto cp_data; - - case 0xBD: // CP LXY - data = BYTE( ixy ); - goto cp_data; - - // LD - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r - data = R8( data, 0x70 ); - if ( 0 ) - case 0x36: // LD (IXY+disp),imm - pc++, data = READ_CODE( pc ); - pc++; - WRITE_MEM( IXY_DISP( ixy, SBYTE( data2 ) ), data ); - goto loop; - - CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY - R8( data >> 3, 8 ) = ixy >> 8; - goto loop; - - case 0x64: // LD HXY,HXY - case 0x6D: // LD LXY,LXY - goto loop; - - CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY - R8( data >> 3, 8 ) = ixy; - goto loop; - - CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp) - pc++; - R8( data >> 3, 8 ) = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto loop; - - case 0x26: // LD HXY,imm - pc++; - goto ld_hxy_data; - - case 0x65: // LD HXY,LXY - data2 = BYTE( ixy ); - goto ld_hxy_data; - - CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r - data2 = R8( data, 0x60 ); - ld_hxy_data: - ixy = BYTE( ixy ) + (data2 << 8); - goto set_ixy; - - case 0x2E: // LD LXY,imm - pc++; - goto ld_lxy_data; - - case 0x6C: // LD LXY,HXY - data2 = ixy >> 8; - goto ld_lxy_data; - - CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r - data2 = R8( data, 0x68 ); - ld_lxy_data: - ixy = (ixy & 0xFF00) + data2; - set_ixy: - if ( opcode == 0xDD ) - { - ix = ixy; - goto loop; - } - iy = ixy; - goto loop; - - case 0xF9: // LD SP,IXY - sp = ixy; - goto loop; - - case 0x22:{// LD (ADDR),IXY - int addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, ixy ); - goto loop; - } - - case 0x21: // LD IXY,imm - ixy = GET_ADDR(); - pc += 2; - goto set_ixy; - - case 0x2A:{// LD IXY,(addr) - int addr = GET_ADDR(); - ixy = READ_WORD( addr ); - pc += 2; - goto set_ixy; - } - - // DD/FD CB prefix - case 0xCB: { - data = IXY_DISP( ixy, SBYTE( data2 ) ); - pc++; - data2 = READ_CODE( pc ); - pc++; - switch ( data2 ) - { - case 0x06: goto rlc_data_addr; // RLC (IXY) - case 0x16: goto rl_data_addr; // RL (IXY) - case 0x26: goto sla_data_addr; // SLA (IXY) - case 0x36: goto sll_data_addr; // SLL (IXY) - case 0x0E: goto rrc_data_addr; // RRC (IXY) - case 0x1E: goto rr_data_addr; // RR (IXY) - case 0x2E: goto sra_data_addr; // SRA (IXY) - case 0x3E: goto srl_data_addr; // SRL (IXY) - - CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp) - int temp = READ_MEM( data ); - temp = temp & (1 << (data2 >> 3 & 7)); - flags = (flags & C01) + H10 + (temp & S80); - flags += (unsigned) --temp >> 8 & (Z40 | P04); - goto loop; - } - - CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp) - CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp) - int temp = READ_MEM( data ); - int bit = 1 << (data2 >> 3 & 7); - temp |= bit; // SET - if ( !(data2 & 0x40) ) - temp ^= bit; // RES - WRITE_MEM( data, temp ); - goto loop; - } - - default: - dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); - warning = true; - goto loop; - } - assert( false ); - } - - // INC/DEC - case 0x23: // INC IXY - ixy = WORD( ixy + 1 ); - goto set_ixy; - - case 0x2B: // DEC IXY - ixy = WORD( ixy - 1 ); - goto set_ixy; - - case 0x34: // INC (IXY+disp) - ixy = IXY_DISP( ixy, SBYTE( data2 ) ); - pc++; - data = READ_MEM( ixy ) + 1; - WRITE_MEM( ixy, data ); - goto inc_set_flags; - - case 0x35: // DEC (IXY+disp) - ixy = IXY_DISP( ixy, SBYTE( data2 ) ); - pc++; - data = READ_MEM( ixy ) - 1; - WRITE_MEM( ixy, data ); - goto dec_set_flags; - - case 0x24: // INC HXY - ixy = WORD( ixy + 0x100 ); - data = ixy >> 8; - goto inc_xy_common; - - case 0x2C: // INC LXY - data = BYTE( ixy + 1 ); - ixy = (ixy & 0xFF00) + data; - inc_xy_common: - if ( opcode == 0xDD ) - { - ix = ixy; - goto inc_set_flags; - } - iy = ixy; - goto inc_set_flags; - - case 0x25: // DEC HXY - ixy = WORD( ixy - 0x100 ); - data = ixy >> 8; - goto dec_xy_common; - - case 0x2D: // DEC LXY - data = BYTE( ixy - 1 ); - ixy = (ixy & 0xFF00) + data; - dec_xy_common: - if ( opcode == 0xDD ) - { - ix = ixy; - goto dec_set_flags; - } - iy = ixy; - goto dec_set_flags; - - // PUSH/POP - case 0xE5: // PUSH IXY - data = ixy; - goto push_data; - - case 0xE1:{// POP IXY - ixy = READ_WORD( sp ); - sp = WORD( sp + 2 ); - goto set_ixy; - } - - // Misc - - case 0xE9: // JP (IXY) - pc = ixy; - goto loop; - - case 0xE3:{// EX (SP),IXY - int temp = READ_WORD( sp ); - WRITE_WORD( sp, ixy ); - ixy = temp; - goto set_ixy; - } - - default: - dprintf( "Unnecessary DD/FD prefix encountered\n" ); - warning = true; - pc--; - goto loop; - } - assert( false ); - } - - } - dprintf( "Unhandled main opcode: $%02X\n", opcode ); - assert( false ); - -#ifdef IDLE_ADDR -hit_idle_addr: - s_time -= 11; - goto out_of_time; -#endif -halt: - s_time &= 3; // increment by multiple of 4 -out_of_time: - pc--; - - r.b.flags = flags; - R.ix = ix; - R.iy = iy; - R.sp = sp; - R.pc = pc; - R.b = r.b; - - cpu->cpu_state_.base = s.base; - cpu->cpu_state_.time = s_time; - cpu->cpu_state = &cpu->cpu_state_; -} +// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ + +// Last validated with zexall 2009.12.05. +// Doesn't implement the R register or immediate interrupt after EI. +// Address wrap-around isn't completely correct, but is prevented from crashing emulator. +// 16-bit memory accesses are made directly to mapped memory, instead of using macro. + +#if 0 +/* Define these macros in the source file before #including this file. +- Parameters might be expressions, so they are best evaluated only once, +though they NEVER have side-effects, so multiple evaluation is OK. +- Output parameters might be a multiple-assignment expression like "a=x", +so they must NOT be parenthesized. +- Except where noted, time() and related functions will NOT work +correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and +CACHE_TIME() the normal time changing functions can be used. +- Macros "returning" void may use a {} statement block. */ + + // 0 <= addr <= 0xFFFF + 0x100 + // Optional; default uses whatever was set with map_mem() + int READ_MEM( addr_t ); + void WRITE_MEM( addr_t, int data ); + + // 0 <= port <= 0xFFFF (apparently upper 8 bits are output by hardware) + void OUT_PORT( int port, int data ); + int IN_PORT int port ); + + // Reference to Z80_Cpu object used for emulation + #define CPU cpu + +// The following can be used within macros: + + // Current time + time_t TIME(); + + // Allows use of time functions + void FLUSH_TIME(); + + // Must be used before end of macro if FLUSH_TIME() was used earlier + void CACHE_TIME(); + +// Configuration (optional; commented behavior if defined) + + // Optimizes as if map_mem( 0, 0x10000, FLAT_MEM, FLAT_MEM ) is always in effect + #define FLAT_MEM my_mem_array + + // If RST 7 ($FF) is encountered and PC = IDLE_ADDR, stops execution + #define IDLE_ADDR 0x1234 + + // Expanded just before beginning of code, to help debugger + #define CPU_BEGIN void my_run_cpu() { + +#endif + +/* Copyright (C) 2006-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifdef CPU_BEGIN + CPU_BEGIN +#endif + +#define R cpu->r + +// flags, named with hex value for clarity +int const S80 = 0x80; +int const Z40 = 0x40; +int const F20 = 0x20; +int const H10 = 0x10; +int const F08 = 0x08; +int const V04 = 0x04; +int const P04 = 0x04; +int const N02 = 0x02; +int const C01 = 0x01; + +#define SZ28P( n ) cpu->szpc [n] +#define SZ28PC( n ) cpu->szpc [n] +#define SZ28C( n ) (cpu->szpc [n] & ~P04) +#define SZ28( n ) SZ28C( n ) + +#define SET_R( n ) (void) (R.r = n) +#define GET_R() (R.r) + +// Time +#define TIME() (s_time + s.base) +#define FLUSH_TIME() {s.time = s_time;} +#define CACHE_TIME() {s_time = s.time;} + +// Memory +#define RW_MEM( addr, rw ) RW_PAGE( addr, rw ) [RW_OFFSET( addr )] +#define READ_CODE( addr ) RW_MEM( addr, read ) + +#ifdef FLAT_MEM + #define RW_PAGE( addr, rw ) FLAT_MEM + #define RW_OFFSET( addr ) (addr) + #define INSTR( off, addr ) READ_CODE( addr ) +#else + #define RW_PAGE( addr, rw ) s.rw [(unsigned) (addr) >> page_bits] + #define RW_OFFSET( addr ) Z80_CPU_OFFSET( addr ) + #define INSTR( off, addr ) instr [off] +#endif + +#ifndef READ_MEM + #define READ_MEM( addr ) RW_MEM( addr, read ) +#endif + +#ifndef WRITE_MEM + #define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data) +#endif + +#define READ_WORD( addr ) GET_LE16( &RW_MEM( addr, read ) ) +#define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data ) + +// Truncation +#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ +#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ +#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ + +// Misc +#define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e +#define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f +#define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g +#define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h + +#ifdef BLARGG_BIG_ENDIAN + #define R8( n, offset ) ((r.r8_ - offset) [n]) +#elif BLARGG_LITTLE_ENDIAN + #define R8( n, offset ) ((r.r8_ - offset) [(n) ^ 1]) +#else + #error "Byte order of CPU must be known" +#endif + +#define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)]) + +#define EX( x, y ) \ + {\ + int temp = x;\ + x = y;\ + y = temp;\ + } + +#define EXX( name ) \ + EX( R.alt.name, r.name ) + +bool warning = false; +{ + struct cpu_state_t s; + #ifdef FLAT_MEM + s.base = cpu->cpu_state_.base; + #else + s = cpu->cpu_state_; + #endif + cpu->cpu_state = &s; + + + union r_t { + struct regs_t b; + struct pairs_t w; + byte r8_ [8]; // indexed + uint16_t r16_ [4]; + } r; + r.b = R.b; + + cpu_time_t s_time = cpu->cpu_state_.time; + int pc = R.pc; + int sp = R.sp; + int ix = R.ix; // TODO: keep in memory for direct access? + int iy = R.iy; + int flags = R.b.flags; + + //goto loop; // confuses optimizer + s_time += 7; + pc -= 2; + +call_not_taken: + s_time -= 7; +jp_not_taken: + pc += 2; +loop: + + check( (unsigned) pc < 0x10000 + 1 ); // +1 so emulator can catch wrap-around + check( (unsigned) sp < 0x10000 ); + check( (unsigned) flags < 0x100 ); + check( (unsigned) ix < 0x10000 ); + check( (unsigned) iy < 0x10000 ); + + byte const* instr = RW_PAGE( pc, read ); + + int opcode; + + if ( RW_OFFSET( ~0 ) == ~0 ) + { + opcode = instr [RW_OFFSET( pc )]; + pc++; + instr += RW_OFFSET( pc ); + } + else + { + instr += RW_OFFSET( pc ); + opcode = *instr++; + pc++; + } + + static byte const clock_table [256 * 2] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0 + 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1 + 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, // 2 + 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, // 3 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6 + 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B + 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C + 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D + 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E + 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F + + // high four bits are $ED time - 8, low four bits are $DD/$FD time - 8 + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00, + 0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, + 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, + 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, + 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0, + 0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, + 0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00, + 0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + }; + + if ( s_time >= 0 ) + goto out_of_time; + s_time += clock_table [opcode]; + + #ifdef Z80_CPU_LOG_H + //log_opcode( opcode, READ_CODE( pc ) ); + z80_cpu_log( "log.txt", pc - 1, opcode, READ_CODE( pc ), + READ_CODE( pc + 1 ), READ_CODE( pc + 2 ) ); + z80_log_regs( r.b.a, r.w.bc, r.w.de, r.w.hl, sp, ix, iy ); + #endif + +#define GET_ADDR() GET_LE16( &INSTR( 0, pc ) ) + + int data; + data = INSTR( 0, pc ); + + switch ( opcode ) + { +// Common + + case 0x00: // NOP + CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc. + goto loop; + + case 0x08:{// EX AF,AF' + EXX( b.a ); + EX( R.alt.b.flags, flags ); + goto loop; + } + + case 0xD3: // OUT (imm),A + pc++; + OUT_PORT( (data + r.b.a * 0x100), r.b.a ); + goto loop; + + case 0x2E: // LD L,imm + pc++; + r.b.l = data; + goto loop; + + case 0x3E: // LD A,imm + pc++; + r.b.a = data; + goto loop; + + case 0x3A:{// LD A,(addr) + int addr = GET_ADDR(); + pc += 2; + r.b.a = READ_MEM( addr ); + goto loop; + } + +// Conditional + +#define ZERO (flags & Z40) +#define CARRY (flags & C01) +#define EVEN (flags & P04) +#define MINUS (flags & S80) + +// JR +// TODO: more efficient way to handle negative branch that wraps PC around +#define JR_( cond, clocks ) {\ + pc++;\ + if ( !(cond) )\ + goto loop;\ + int offset = SBYTE( data );\ + pc = WORD( pc + offset );\ + s_time += clocks;\ + goto loop;\ +} + +#define JR( cond ) JR_( cond, 5 ) + + case 0x20: JR( !ZERO ) // JR NZ,disp + case 0x28: JR( ZERO ) // JR Z,disp + case 0x30: JR( !CARRY ) // JR NC,disp + case 0x38: JR( CARRY ) // JR C,disp + case 0x18: JR_( true,0) // JR disp + + case 0x10:{// DJNZ disp + int temp = r.b.b - 1; + r.b.b = temp; + JR( temp ) + } + +// JP +#define JP( cond ) \ + if ( !(cond) )\ + goto jp_not_taken;\ + pc = GET_ADDR();\ + goto loop; + + case 0xC2: JP( !ZERO ) // JP NZ,addr + case 0xCA: JP( ZERO ) // JP Z,addr + case 0xD2: JP( !CARRY ) // JP NC,addr + case 0xDA: JP( CARRY ) // JP C,addr + case 0xE2: JP( !EVEN ) // JP PO,addr + case 0xEA: JP( EVEN ) // JP PE,addr + case 0xF2: JP( !MINUS ) // JP P,addr + case 0xFA: JP( MINUS ) // JP M,addr + + case 0xC3: // JP addr + pc = GET_ADDR(); + goto loop; + + case 0xE9: // JP HL + pc = r.w.hl; + goto loop; + +// RET +#define RET( cond ) \ + if ( cond )\ + goto ret_taken;\ + s_time -= 6;\ + goto loop; + + case 0xC0: RET( !ZERO ) // RET NZ + case 0xC8: RET( ZERO ) // RET Z + case 0xD0: RET( !CARRY ) // RET NC + case 0xD8: RET( CARRY ) // RET C + case 0xE0: RET( !EVEN ) // RET PO + case 0xE8: RET( EVEN ) // RET PE + case 0xF0: RET( !MINUS ) // RET P + case 0xF8: RET( MINUS ) // RET M + + case 0xC9: // RET + ret_taken: + pc = READ_WORD( sp ); + sp = WORD( sp + 2 ); + goto loop; + +// CALL +#define CALL( cond ) \ + if ( cond )\ + goto call_taken;\ + goto call_not_taken; + + case 0xC4: CALL( !ZERO ) // CALL NZ,addr + case 0xCC: CALL( ZERO ) // CALL Z,addr + case 0xD4: CALL( !CARRY ) // CALL NC,addr + case 0xDC: CALL( CARRY ) // CALL C,addr + case 0xE4: CALL( !EVEN ) // CALL PO,addr + case 0xEC: CALL( EVEN ) // CALL PE,addr + case 0xF4: CALL( !MINUS ) // CALL P,addr + case 0xFC: CALL( MINUS ) // CALL M,addr + + case 0xCD:{// CALL addr + call_taken: { + int addr = pc + 2; + pc = GET_ADDR(); + sp = WORD( sp - 2 ); + WRITE_WORD( sp, addr ); + goto loop; + } + } + + case 0xFF: // RST + #ifdef IDLE_ADDR + if ( pc == IDLE_ADDR + 1 ) + goto hit_idle_addr; + #else + if ( pc > 0x10000 ) + { + pc = WORD( pc - 1 ); + s_time -= 11; + goto loop; + } + #endif + CASE7( C7, CF, D7, DF, E7, EF, F7 ): + data = pc; + pc = opcode & 0x38; + #ifdef RST_BASE + pc += RST_BASE; + #endif + goto push_data; + +// PUSH/POP + case 0xF5: // PUSH AF + data = r.b.a * 0x100u + flags; + goto push_data; + + case 0xC5: // PUSH BC + case 0xD5: // PUSH DE + case 0xE5: // PUSH HL + data = R16( opcode, 4, 0xC5 ); + push_data: + sp = WORD( sp - 2 ); + WRITE_WORD( sp, data ); + goto loop; + + case 0xF1: // POP AF + flags = READ_MEM( sp ); + r.b.a = READ_MEM( (sp + 1) ); + sp = WORD( sp + 2 ); + goto loop; + + case 0xC1: // POP BC + case 0xD1: // POP DE + case 0xE1: // POP HL + R16( opcode, 4, 0xC1 ) = READ_WORD( sp ); + sp = WORD( sp + 2 ); + goto loop; + +// ADC/ADD/SBC/SUB + case 0x96: // SUB (HL) + case 0x86: // ADD (HL) + flags &= ~C01; + case 0x9E: // SBC (HL) + case 0x8E: // ADC (HL) + data = READ_MEM( r.w.hl ); + goto adc_data; + + case 0xD6: // SUB A,imm + case 0xC6: // ADD imm + flags &= ~C01; + case 0xDE: // SBC A,imm + case 0xCE: // ADC imm + pc++; + goto adc_data; + + CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r + CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r + flags &= ~C01; + CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r + CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r + data = R8( opcode & 7, 0 ); + adc_data: { + int result = data + (flags & C01); + data ^= r.b.a; + flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes + if ( flags ) + result = -result; + result += r.b.a; + data ^= result; + flags +=(data & H10) + + ((data + 0x80) >> 6 & V04) + + SZ28C( result & 0x1FF ); + r.b.a = result; + goto loop; + } + +// CP + case 0xBE: // CP (HL) + data = READ_MEM( r.w.hl ); + goto cp_data; + + case 0xFE: // CP imm + pc++; + goto cp_data; + + CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r + data = R8( opcode, 0xB8 ); + cp_data: { + int result = r.b.a - data; + flags = N02 + (data & (F20 | F08)) + (result >> 8 & C01); + data ^= r.b.a; + flags +=(((result ^ r.b.a) & data) >> 5 & V04) + + (((data & H10) ^ result) & (S80 | H10)); + if ( BYTE( result ) ) + goto loop; + flags += Z40; + goto loop; + } + +// ADD HL,r.w + + case 0x39: // ADD HL,SP + data = sp; + goto add_hl_data; + + case 0x09: // ADD HL,BC + case 0x19: // ADD HL,DE + case 0x29: // ADD HL,HL + data = R16( opcode, 4, 0x09 ); + add_hl_data: { + int sum = r.w.hl + data; + data ^= r.w.hl; + r.w.hl = sum; + flags = (flags & (S80 | Z40 | V04)) + + (sum >> 16) + + (sum >> 8 & (F20 | F08)) + + ((data ^ sum) >> 8 & H10); + goto loop; + } + + case 0x27:{// DAA + int a = r.b.a; + if ( a > 0x99 ) + flags |= C01; + + int adjust = 0x60 * (flags & C01); + + if ( flags & H10 || (a & 0x0F) > 9 ) + adjust += 0x06; + + if ( flags & N02 ) + adjust = -adjust; + a += adjust; + + flags = (flags & (C01 | N02)) + + ((r.b.a ^ a) & H10) + + SZ28P( BYTE( a ) ); + r.b.a = a; + goto loop; + } + +// INC/DEC + case 0x34: // INC (HL) + data = READ_MEM( r.w.hl ) + 1; + WRITE_MEM( r.w.hl, data ); + goto inc_set_flags; + + CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r + data = ++R8( opcode >> 3, 0 ); + inc_set_flags: + flags = (flags & C01) + + (((data & 0x0F) - 1) & H10) + + SZ28( BYTE( data ) ); + if ( data != 0x80 ) + goto loop; + flags += V04; + goto loop; + + case 0x35: // DEC (HL) + data = READ_MEM( r.w.hl ) - 1; + WRITE_MEM( r.w.hl, data ); + goto dec_set_flags; + + CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r + data = --R8( opcode >> 3, 0 ); + dec_set_flags: + flags = (flags & C01) + N02 + + (((data & 0x0F) + 1) & H10) + + SZ28( BYTE( data ) ); + if ( data != 0x7F ) + goto loop; + flags += V04; + goto loop; + + case 0x03: // INC BC + case 0x13: // INC DE + case 0x23: // INC HL + R16( opcode, 4, 0x03 )++; + goto loop; + + case 0x33: // INC SP + sp = WORD( sp + 1 ); + goto loop; + + case 0x0B: // DEC BC + case 0x1B: // DEC DE + case 0x2B: // DEC HL + R16( opcode, 4, 0x0B )--; + goto loop; + + case 0x3B: // DEC SP + sp = WORD( sp - 1 ); + goto loop; + +// AND + case 0xA6: // AND (HL) + data = READ_MEM( r.w.hl ); + goto and_data; + + case 0xE6: // AND imm + pc++; + goto and_data; + + CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r + data = R8( opcode, 0xA0 ); + and_data: + r.b.a &= data; + flags = SZ28P( r.b.a ) + H10; + goto loop; + +// OR + case 0xB6: // OR (HL) + data = READ_MEM( r.w.hl ); + goto or_data; + + case 0xF6: // OR imm + pc++; + goto or_data; + + CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r + data = R8( opcode, 0xB0 ); + or_data: + r.b.a |= data; + flags = SZ28P( r.b.a ); + goto loop; + +// XOR + case 0xAE: // XOR (HL) + data = READ_MEM( r.w.hl ); + goto xor_data; + + case 0xEE: // XOR imm + pc++; + goto xor_data; + + CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r + data = R8( opcode, 0xA8 ); + xor_data: + r.b.a ^= data; + flags = SZ28P( r.b.a ); + goto loop; + +// LD + CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r + WRITE_MEM( r.w.hl, R8( opcode, 0x70 ) ); + goto loop; + + CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r + CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r + CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r + CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r + CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r + CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r + CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r + R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 ); + goto loop; + + CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm + R8( opcode >> 3, 0 ) = data; + pc++; + goto loop; + + case 0x36: // LD (HL),imm + pc++; + WRITE_MEM( r.w.hl, data ); + goto loop; + + CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL) + R8( opcode >> 3, 8 ) = READ_MEM( r.w.hl ); + goto loop; + + case 0x01: // LD r.w,imm + case 0x11: + case 0x21: + R16( opcode, 4, 0x01 ) = GET_ADDR(); + pc += 2; + goto loop; + + case 0x31: // LD sp,imm + sp = GET_ADDR(); + pc += 2; + goto loop; + + case 0x2A:{// LD HL,(addr) + int addr = GET_ADDR(); + pc += 2; + r.w.hl = READ_WORD( addr ); + goto loop; + } + + case 0x32:{// LD (addr),A + int addr = GET_ADDR(); + pc += 2; + WRITE_MEM( addr, r.b.a ); + goto loop; + } + + case 0x22:{// LD (addr),HL + int addr = GET_ADDR(); + pc += 2; + WRITE_WORD( addr, r.w.hl ); + goto loop; + } + + case 0x02: // LD (BC),A + case 0x12: // LD (DE),A + WRITE_MEM( R16( opcode, 4, 0x02 ), r.b.a ); + goto loop; + + case 0x0A: // LD A,(BC) + case 0x1A: // LD A,(DE) + r.b.a = READ_MEM( R16( opcode, 4, 0x0A ) ); + goto loop; + + case 0xF9: // LD SP,HL + sp = r.w.hl; + goto loop; + +// Rotate + + case 0x07:{// RLCA + int temp = r.b.a; + temp = (temp << 1) + (temp >> 7); + flags = (flags & (S80 | Z40 | P04)) + + (temp & (F20 | F08 | C01)); + r.b.a = temp; + goto loop; + } + + case 0x0F:{// RRCA + int temp = r.b.a; + flags = (flags & (S80 | Z40 | P04)) + + (temp & C01); + temp = (temp << 7) + (temp >> 1); + flags += temp & (F20 | F08); + r.b.a = temp; + goto loop; + } + + case 0x17:{// RLA + int temp = (r.b.a << 1) + (flags & C01); + flags = (flags & (S80 | Z40 | P04)) + + (temp & (F20 | F08)) + + (temp >> 8); + r.b.a = temp; + goto loop; + } + + case 0x1F:{// RRA + int temp = (flags << 7) + (r.b.a >> 1); + flags = (flags & (S80 | Z40 | P04)) + + (temp & (F20 | F08)) + + (r.b.a & C01); + r.b.a = temp; + goto loop; + } + +// Misc + case 0x2F:{// CPL + int temp = ~r.b.a; + flags = (flags & (S80 | Z40 | P04 | C01)) + + (temp & (F20 | F08)) + + (H10 | N02); + r.b.a = temp; + goto loop; + } + + case 0x3F:{// CCF + flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) + + (flags << 4 & H10) + + (r.b.a & (F20 | F08)); + goto loop; + } + + case 0x37: // SCF + flags = ((flags & (S80 | Z40 | P04)) | C01) + + (r.b.a & (F20 | F08)); + goto loop; + + case 0xDB: // IN A,(imm) + pc++; + r.b.a = IN_PORT( (data + r.b.a * 0x100) ); + goto loop; + + case 0xE3:{// EX (SP),HL + int temp = READ_WORD( sp ); + WRITE_WORD( sp, r.w.hl ); + r.w.hl = temp; + goto loop; + } + + case 0xEB: // EX DE,HL + EX( r.w.hl, r.w.de ); + goto loop; + + case 0xD9: // EXX DE,HL + EXX( w.bc ); + EXX( w.de ); + EXX( w.hl ); + goto loop; + + case 0xF3: // DI + R.iff1 = 0; + R.iff2 = 0; + goto loop; + + case 0xFB: // EI + R.iff1 = 1; + R.iff2 = 1; + // TODO: delayed effect + goto loop; + + case 0x76: // HALT + goto halt; + +//////////////////////////////////////// CB prefix + { + case 0xCB: + pc++; + switch ( data ) + { + + // Rotate left + + #define RLC( read, write ) {\ + int result = read;\ + result = BYTE( result << 1 ) + (result >> 7);\ + flags = SZ28P( result ) + (result & C01);\ + write;\ + goto loop;\ + } + + case 0x06: // RLC (HL) + s_time += 7; + data = r.w.hl; + rlc_data_addr: + RLC( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r + byte* reg = &R8( data, 0 ); + RLC( *reg, *reg = result ) + } + + #define RL( read, write ) {\ + int result = (read << 1) + (flags & C01);\ + flags = SZ28PC( result );\ + write;\ + goto loop;\ + } + + case 0x16: // RL (HL) + s_time += 7; + data = r.w.hl; + rl_data_addr: + RL( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r + byte* reg = &R8( data, 0x10 ); + RL( *reg, *reg = result ) + } + + #define SLA( read, low_bit, write ) {\ + int result = (read << 1) + low_bit;\ + flags = SZ28PC( result );\ + write;\ + goto loop;\ + } + + case 0x26: // SLA (HL) + s_time += 7; + data = r.w.hl; + sla_data_addr: + SLA( READ_MEM( data ), 0, WRITE_MEM( data, result ) ) + + CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r + byte* reg = &R8( data, 0x20 ); + SLA( *reg, 0, *reg = result ) + } + + case 0x36: // SLL (HL) + s_time += 7; + data = r.w.hl; + sll_data_addr: + SLA( READ_MEM( data ), 1, WRITE_MEM( data, result ) ) + + CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r + byte* reg = &R8( data, 0x30 ); + SLA( *reg, 1, *reg = result ) + } + + // Rotate right + + #define RRC( read, write ) {\ + int result = read;\ + flags = result & C01;\ + result = BYTE( result << 7 ) + (result >> 1);\ + flags += SZ28P( result );\ + write;\ + goto loop;\ + } + + case 0x0E: // RRC (HL) + s_time += 7; + data = r.w.hl; + rrc_data_addr: + RRC( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r + byte* reg = &R8( data, 0x08 ); + RRC( *reg, *reg = result ) + } + + #define RR( read, write ) {\ + int result = read;\ + int temp = result & C01;\ + result = BYTE( flags << 7 ) + (result >> 1);\ + flags = SZ28P( result ) + temp;\ + write;\ + goto loop;\ + } + + case 0x1E: // RR (HL) + s_time += 7; + data = r.w.hl; + rr_data_addr: + RR( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r + byte* reg = &R8( data, 0x18 ); + RR( *reg, *reg = result ) + } + + #define SRA( read, write ) {\ + int result = read;\ + flags = result & C01;\ + result = (result & 0x80) + (result >> 1);\ + flags += SZ28P( result );\ + write;\ + goto loop;\ + } + + case 0x2E: // SRA (HL) + data = r.w.hl; + s_time += 7; + sra_data_addr: + SRA( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r + byte* reg = &R8( data, 0x28 ); + SRA( *reg, *reg = result ) + } + + #define SRL( read, write ) {\ + int result = read;\ + flags = result & C01;\ + result >>= 1;\ + flags += SZ28P( result );\ + write;\ + goto loop;\ + } + + case 0x3E: // SRL (HL) + s_time += 7; + data = r.w.hl; + srl_data_addr: + SRL( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r + byte* reg = &R8( data, 0x38 ); + SRL( *reg, *reg = result ) + } + + // BIT + { + int temp; + CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL) + s_time += 4; + temp = READ_MEM( r.w.hl ); + flags &= C01; + goto bit_temp; + CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r + CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r + CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r + CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r + CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r + CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r + CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r + CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r + temp = R8( data & 7, 0 ); + flags = (flags & C01) + (temp & (F20 | F08)); + bit_temp: + temp = temp & (1 << (data >> 3 & 7)); + flags += (temp & S80) + H10; + flags += (unsigned) --temp >> 8 & (Z40 | P04); + goto loop; + } + + // SET/RES + CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL) + CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL) + s_time += 7; + int temp = READ_MEM( r.w.hl ); + int bit = 1 << (data >> 3 & 7); + temp |= bit; // SET + if ( !(data & 0x40) ) + temp ^= bit; // RES + WRITE_MEM( r.w.hl, temp ); + goto loop; + } + + CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r + CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r + CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r + CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r + CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r + CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r + CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r + CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r + R8( data & 7, 0 ) |= 1 << (data >> 3 & 7); + goto loop; + + CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r + CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r + CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r + CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r + CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r + CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r + CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r + CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r + R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7)); + goto loop; + } + assert( false ); + } + +#undef GET_ADDR +#define GET_ADDR() GET_LE16( &INSTR( 1, pc ) ) + +//////////////////////////////////////// ED prefix + { + case 0xED: + pc++; + s_time += (clock_table + 256) [data] >> 4; + switch ( data ) + { + { + int temp; + case 0x72: // SBC HL,SP + case 0x7A: // ADC HL,SP + temp = sp; + if ( 0 ) + case 0x42: // SBC HL,BC + case 0x52: // SBC HL,DE + case 0x62: // SBC HL,HL + case 0x4A: // ADC HL,BC + case 0x5A: // ADC HL,DE + case 0x6A: // ADC HL,HL + temp = R16( data >> 3 & 6, 1, 0 ); + int sum = temp + (flags & C01); + flags = ~data >> 2 & N02; + if ( flags ) + sum = -sum; + sum += r.w.hl; + temp ^= r.w.hl; + temp ^= sum; + flags +=(sum >> 16 & C01) + + (temp >> 8 & H10) + + (sum >> 8 & (S80 | F20 | F08)) + + ((temp + 0x8000) >> 14 & V04); + r.w.hl = sum; + if ( WORD( sum ) ) + goto loop; + flags += Z40; + goto loop; + } + + CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C) + int temp = IN_PORT( r.w.bc ); + R8( data >> 3, 8 ) = temp; + flags = (flags & C01) + SZ28P( temp ); + goto loop; + } + + case 0x71: // OUT (C),0 + r.b.flags = 0; + CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r + OUT_PORT( r.w.bc, R8( data >> 3, 8 ) ); + goto loop; + + { + int temp; + case 0x73: // LD (ADDR),SP + temp = sp; + if ( 0 ) + case 0x43: // LD (ADDR),BC + case 0x53: // LD (ADDR),DE + temp = R16( data, 4, 0x43 ); + int addr = GET_ADDR(); + pc += 2; + WRITE_WORD( addr, temp ); + goto loop; + } + + case 0x4B: // LD BC,(ADDR) + case 0x5B:{// LD DE,(ADDR) + int addr = GET_ADDR(); + pc += 2; + R16( data, 4, 0x4B ) = READ_WORD( addr ); + goto loop; + } + + case 0x7B:{// LD SP,(ADDR) + int addr = GET_ADDR(); + pc += 2; + sp = READ_WORD( addr ); + goto loop; + } + + case 0x67:{// RRD + int temp = READ_MEM( r.w.hl ); + WRITE_MEM( r.w.hl, ((r.b.a << 4) + (temp >> 4)) ); + temp = (r.b.a & 0xF0) + (temp & 0x0F); + flags = (flags & C01) + SZ28P( temp ); + r.b.a = temp; + goto loop; + } + + case 0x6F:{// RLD + int temp = READ_MEM( r.w.hl ); + WRITE_MEM( r.w.hl, ((temp << 4) + (r.b.a & 0x0F)) ); + temp = (r.b.a & 0xF0) + (temp >> 4); + flags = (flags & C01) + SZ28P( temp ); + r.b.a = temp; + goto loop; + } + + CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG + opcode = 0x10; // flag to do SBC instead of ADC + flags &= ~C01; + data = r.b.a; + r.b.a = 0; + goto adc_data; + + { + int inc; + case 0xA9: // CPD + case 0xB9: // CPDR + inc = -1; + if ( 0 ) + case 0xA1: // CPI + case 0xB1: // CPIR + inc = +1; + int addr = r.w.hl; + r.w.hl = addr + inc; + int temp = READ_MEM( addr ); + + int result = r.b.a - temp; + flags = (flags & C01) + N02 + + ((((temp ^ r.b.a) & H10) ^ result) & (S80 | H10)); + + if ( !BYTE( result ) ) + flags += Z40; + result -= (flags & H10) >> 4; + flags += result & F08; + flags += result << 4 & F20; + if ( !--r.w.bc ) + goto loop; + + flags += V04; + if ( flags & Z40 || data < 0xB0 ) + goto loop; + + pc -= 2; + s_time += 5; + goto loop; + } + + { + int inc; + case 0xA8: // LDD + case 0xB8: // LDDR + inc = -1; + if ( 0 ) + case 0xA0: // LDI + case 0xB0: // LDIR + inc = +1; + int addr = r.w.hl; + r.w.hl = addr + inc; + int temp = READ_MEM( addr ); + + addr = r.w.de; + r.w.de = addr + inc; + WRITE_MEM( addr, temp ); + + temp += r.b.a; + flags = (flags & (S80 | Z40 | C01)) + + (temp & F08) + (temp << 4 & F20); + if ( !--r.w.bc ) + goto loop; + + flags += V04; + if ( data < 0xB0 ) + goto loop; + + pc -= 2; + s_time += 5; + goto loop; + } + + { + int inc; + case 0xAB: // OUTD + case 0xBB: // OTDR + inc = -1; + if ( 0 ) + case 0xA3: // OUTI + case 0xB3: // OTIR + inc = +1; + int addr = r.w.hl; + r.w.hl = addr + inc; + int temp = READ_MEM( addr ); + + int b = --r.b.b; + flags = (temp >> 6 & N02) + SZ28( b ); + if ( b && data >= 0xB0 ) + { + pc -= 2; + s_time += 5; + } + + OUT_PORT( r.w.bc, temp ); + goto loop; + } + + { + int inc; + case 0xAA: // IND + case 0xBA: // INDR + inc = -1; + if ( 0 ) + case 0xA2: // INI + case 0xB2: // INIR + inc = +1; + + int addr = r.w.hl; + r.w.hl = addr + inc; + + int temp = IN_PORT( r.w.bc ); + + int b = --r.b.b; + flags = (temp >> 6 & N02) + SZ28( b ); + if ( b && data >= 0xB0 ) + { + pc -= 2; + s_time += 5; + } + + WRITE_MEM( addr, temp ); + goto loop; + } + + case 0x47: // LD I,A + R.i = r.b.a; + goto loop; + + case 0x4F: // LD R,A + SET_R( r.b.a ); + dprintf( "LD R,A not supported\n" ); + warning = true; + goto loop; + + case 0x57: // LD A,I + r.b.a = R.i; + goto ld_ai_common; + + case 0x5F: // LD A,R + r.b.a = GET_R(); + dprintf( "LD A,R not supported\n" ); + warning = true; + ld_ai_common: + flags = (flags & C01) + SZ28( r.b.a ) + (R.iff2 << 2 & V04); + goto loop; + + CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN + R.iff1 = R.iff2; + goto ret_taken; + + case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0 + R.im = 0; + goto loop; + + case 0x56: case 0x76: // IM 1 + R.im = 1; + goto loop; + + case 0x5E: case 0x7E: // IM 2 + R.im = 2; + goto loop; + + default: + dprintf( "Opcode $ED $%02X not supported\n", data ); + warning = true; + goto loop; + } + assert( false ); + } + +//////////////////////////////////////// DD/FD prefix + { + int ixy; + case 0xDD: + ixy = ix; + goto ix_prefix; + case 0xFD: + ixy = iy; + ix_prefix: + pc++; + int data2 = READ_CODE( pc ); + s_time += (clock_table + 256) [data] & 0x0F; + switch ( data ) + { + // TODO: more efficient way of avoid negative address + // TODO: avoid using this as argument to READ_MEM() since it is evaluated twice + #define IXY_DISP( ixy, disp ) WORD( (ixy ) + (disp)) + + #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in; + + // ADD/ADC/SUB/SBC + + case 0x96: // SUB (IXY+disp) + case 0x86: // ADD (IXY+disp) + flags &= ~C01; + case 0x9E: // SBC (IXY+disp) + case 0x8E: // ADC (IXY+disp) + pc++; + opcode = data; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto adc_data; + + case 0x94: // SUB HXY + case 0x84: // ADD HXY + flags &= ~C01; + case 0x9C: // SBC HXY + case 0x8C: // ADC HXY + opcode = data; + data = ixy >> 8; + goto adc_data; + + case 0x95: // SUB LXY + case 0x85: // ADD LXY + flags &= ~C01; + case 0x9D: // SBC LXY + case 0x8D: // ADC LXY + opcode = data; + data = BYTE( ixy ); + goto adc_data; + + { + int temp; + case 0x39: // ADD IXY,SP + temp = sp; + goto add_ixy_data; + + case 0x29: // ADD IXY,HL + temp = ixy; + goto add_ixy_data; + + case 0x09: // ADD IXY,BC + case 0x19: // ADD IXY,DE + temp = R16( data, 4, 0x09 ); + add_ixy_data: { + int sum = ixy + temp; + temp ^= ixy; + ixy = WORD( sum ); + flags = (flags & (S80 | Z40 | V04)) + + (sum >> 16) + + (sum >> 8 & (F20 | F08)) + + ((temp ^ sum) >> 8 & H10); + goto set_ixy; + } + } + + // AND + case 0xA6: // AND (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto and_data; + + case 0xA4: // AND HXY + data = ixy >> 8; + goto and_data; + + case 0xA5: // AND LXY + data = BYTE( ixy ); + goto and_data; + + // OR + case 0xB6: // OR (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto or_data; + + case 0xB4: // OR HXY + data = ixy >> 8; + goto or_data; + + case 0xB5: // OR LXY + data = BYTE( ixy ); + goto or_data; + + // XOR + case 0xAE: // XOR (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto xor_data; + + case 0xAC: // XOR HXY + data = ixy >> 8; + goto xor_data; + + case 0xAD: // XOR LXY + data = BYTE( ixy ); + goto xor_data; + + // CP + case 0xBE: // CP (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto cp_data; + + case 0xBC: // CP HXY + data = ixy >> 8; + goto cp_data; + + case 0xBD: // CP LXY + data = BYTE( ixy ); + goto cp_data; + + // LD + CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r + data = R8( data, 0x70 ); + if ( 0 ) + case 0x36: // LD (IXY+disp),imm + pc++, data = READ_CODE( pc ); + pc++; + WRITE_MEM( IXY_DISP( ixy, SBYTE( data2 ) ), data ); + goto loop; + + CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY + R8( data >> 3, 8 ) = ixy >> 8; + goto loop; + + case 0x64: // LD HXY,HXY + case 0x6D: // LD LXY,LXY + goto loop; + + CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY + R8( data >> 3, 8 ) = ixy; + goto loop; + + CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp) + pc++; + R8( data >> 3, 8 ) = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto loop; + + case 0x26: // LD HXY,imm + pc++; + goto ld_hxy_data; + + case 0x65: // LD HXY,LXY + data2 = BYTE( ixy ); + goto ld_hxy_data; + + CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r + data2 = R8( data, 0x60 ); + ld_hxy_data: + ixy = BYTE( ixy ) + (data2 << 8); + goto set_ixy; + + case 0x2E: // LD LXY,imm + pc++; + goto ld_lxy_data; + + case 0x6C: // LD LXY,HXY + data2 = ixy >> 8; + goto ld_lxy_data; + + CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r + data2 = R8( data, 0x68 ); + ld_lxy_data: + ixy = (ixy & 0xFF00) + data2; + set_ixy: + if ( opcode == 0xDD ) + { + ix = ixy; + goto loop; + } + iy = ixy; + goto loop; + + case 0xF9: // LD SP,IXY + sp = ixy; + goto loop; + + case 0x22:{// LD (ADDR),IXY + int addr = GET_ADDR(); + pc += 2; + WRITE_WORD( addr, ixy ); + goto loop; + } + + case 0x21: // LD IXY,imm + ixy = GET_ADDR(); + pc += 2; + goto set_ixy; + + case 0x2A:{// LD IXY,(addr) + int addr = GET_ADDR(); + ixy = READ_WORD( addr ); + pc += 2; + goto set_ixy; + } + + // DD/FD CB prefix + case 0xCB: { + data = IXY_DISP( ixy, SBYTE( data2 ) ); + pc++; + data2 = READ_CODE( pc ); + pc++; + switch ( data2 ) + { + case 0x06: goto rlc_data_addr; // RLC (IXY) + case 0x16: goto rl_data_addr; // RL (IXY) + case 0x26: goto sla_data_addr; // SLA (IXY) + case 0x36: goto sll_data_addr; // SLL (IXY) + case 0x0E: goto rrc_data_addr; // RRC (IXY) + case 0x1E: goto rr_data_addr; // RR (IXY) + case 0x2E: goto sra_data_addr; // SRA (IXY) + case 0x3E: goto srl_data_addr; // SRL (IXY) + + CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp) + int temp = READ_MEM( data ); + temp = temp & (1 << (data2 >> 3 & 7)); + flags = (flags & C01) + H10 + (temp & S80); + flags += (unsigned) --temp >> 8 & (Z40 | P04); + goto loop; + } + + CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp) + CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp) + int temp = READ_MEM( data ); + int bit = 1 << (data2 >> 3 & 7); + temp |= bit; // SET + if ( !(data2 & 0x40) ) + temp ^= bit; // RES + WRITE_MEM( data, temp ); + goto loop; + } + + default: + dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); + warning = true; + goto loop; + } + assert( false ); + } + + // INC/DEC + case 0x23: // INC IXY + ixy = WORD( ixy + 1 ); + goto set_ixy; + + case 0x2B: // DEC IXY + ixy = WORD( ixy - 1 ); + goto set_ixy; + + case 0x34: // INC (IXY+disp) + ixy = IXY_DISP( ixy, SBYTE( data2 ) ); + pc++; + data = READ_MEM( ixy ) + 1; + WRITE_MEM( ixy, data ); + goto inc_set_flags; + + case 0x35: // DEC (IXY+disp) + ixy = IXY_DISP( ixy, SBYTE( data2 ) ); + pc++; + data = READ_MEM( ixy ) - 1; + WRITE_MEM( ixy, data ); + goto dec_set_flags; + + case 0x24: // INC HXY + ixy = WORD( ixy + 0x100 ); + data = ixy >> 8; + goto inc_xy_common; + + case 0x2C: // INC LXY + data = BYTE( ixy + 1 ); + ixy = (ixy & 0xFF00) + data; + inc_xy_common: + if ( opcode == 0xDD ) + { + ix = ixy; + goto inc_set_flags; + } + iy = ixy; + goto inc_set_flags; + + case 0x25: // DEC HXY + ixy = WORD( ixy - 0x100 ); + data = ixy >> 8; + goto dec_xy_common; + + case 0x2D: // DEC LXY + data = BYTE( ixy - 1 ); + ixy = (ixy & 0xFF00) + data; + dec_xy_common: + if ( opcode == 0xDD ) + { + ix = ixy; + goto dec_set_flags; + } + iy = ixy; + goto dec_set_flags; + + // PUSH/POP + case 0xE5: // PUSH IXY + data = ixy; + goto push_data; + + case 0xE1:{// POP IXY + ixy = READ_WORD( sp ); + sp = WORD( sp + 2 ); + goto set_ixy; + } + + // Misc + + case 0xE9: // JP (IXY) + pc = ixy; + goto loop; + + case 0xE3:{// EX (SP),IXY + int temp = READ_WORD( sp ); + WRITE_WORD( sp, ixy ); + ixy = temp; + goto set_ixy; + } + + default: + dprintf( "Unnecessary DD/FD prefix encountered\n" ); + warning = true; + pc--; + goto loop; + } + assert( false ); + } + + } + dprintf( "Unhandled main opcode: $%02X\n", opcode ); + assert( false ); + +#ifdef IDLE_ADDR +hit_idle_addr: + s_time -= 11; + goto out_of_time; +#endif +halt: + s_time &= 3; // increment by multiple of 4 +out_of_time: + pc--; + + r.b.flags = flags; + R.ix = ix; + R.iy = iy; + R.sp = sp; + R.pc = pc; + R.b = r.b; + + cpu->cpu_state_.base = s.base; + cpu->cpu_state_.time = s_time; + cpu->cpu_state = &cpu->cpu_state_; +} -- cgit v1.2.3