summaryrefslogtreecommitdiffstats
path: root/apps/codecs/libgme/nes_cpu_run.h
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libgme/nes_cpu_run.h')
-rw-r--r--apps/codecs/libgme/nes_cpu_run.h1122
1 files changed, 0 insertions, 1122 deletions
diff --git a/apps/codecs/libgme/nes_cpu_run.h b/apps/codecs/libgme/nes_cpu_run.h
deleted file mode 100644
index fd1fea9659..0000000000
--- a/apps/codecs/libgme/nes_cpu_run.h
+++ /dev/null
@@ -1,1122 +0,0 @@
-// NES 6502 cpu emulator run function
-
-#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 FLUSH_TIME() and
-CACHE_TIME() allow the time changing functions to work.
-- Macros "returning" void may use a {} statement block. */
-
- // 0 <= addr <= 0xFFFF + page_size
- // time functions can be used
- int READ_MEM( addr_t );
- void WRITE_MEM( addr_t, int data );
- // 0 <= READ_MEM() <= 0xFF
-
- // 0 <= addr <= 0x1FF
- int READ_LOW( addr_t );
- void WRITE_LOW( addr_t, int data );
- // 0 <= READ_LOW() <= 0xFF
-
- // Often-used instructions attempt these before using a normal memory access.
- // Optional; defaults to READ_MEM() and WRITE_MEM()
- bool CAN_READ_FAST( addr_t ); // if true, uses result of READ_FAST
- void READ_FAST( addr_t, int& out ); // ALWAYS called BEFORE CAN_READ_FAST
- bool CAN_WRITE_FAST( addr_t ); // if true, uses WRITE_FAST instead of WRITE_MEM
- void WRITE_FAST( addr_t, int data );
-
- // Used by instructions most often used to access the NES PPU (LDA abs and BIT abs).
- // Optional; defaults to READ_MEM.
- void READ_PPU( addr_t, int& out );
- // 0 <= out <= 0xFF
-
-// 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)
-
- // Emulates dummy reads for indexed instructions
- #define NES_CPU_DUMMY_READS 1
-
- // Optimizes as if map_code( 0, 0x10000 + cpu_padding, FLAT_MEM ) is always in effect
- #define FLAT_MEM my_mem_array
-
- // Expanded just before beginning of code, to help debugger
- #define CPU_BEGIN void my_run_cpu() {
-
-#endif
-
-/* Copyright (C) 2003-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 */
-
-// Allows MWCW debugger to step through code properly
-#ifdef CPU_BEGIN
- CPU_BEGIN
-#endif
-
-// Time
-#define TIME() (s_time + s.base)
-#define FLUSH_TIME() {s.time = s_time - time_offset;}
-#define CACHE_TIME() {s_time = s.time + time_offset;}
-
-// Defaults
-#ifndef CAN_WRITE_FAST
- #define CAN_WRITE_FAST( addr ) 0
- #define WRITE_FAST( addr, data )
-#endif
-
-#ifndef CAN_READ_FAST
- #define CAN_READ_FAST( addr ) 0
- #define READ_FAST( addr, out )
-#endif
-
-#ifndef READ_PPU
- #define READ_PPU( addr, out )\
- {\
- FLUSH_TIME();\
- out = READ_MEM( addr );\
- CACHE_TIME();\
- }
-#endif
-
-#define READ_STACK READ_LOW
-#define WRITE_STACK WRITE_LOW
-
-// Dummy reads
-#ifdef NES_CPU_DUMMY_READS
- // TODO: optimize time handling
- #define DUMMY_READ( addr, idx ) \
- if ( (addr & 0xFF) < idx )\
- {\
- int const time_offset = 1;\
- FLUSH_TIME();\
- READ_MEM( (addr - 0x100) );\
- CACHE_TIME();\
- }
-#else
- #define DUMMY_READ( addr, idx )
-#endif
-
-// Code
-#ifdef FLAT_MEM
- #define CODE_PAGE( addr ) (FLAT_MEM)
- #define CODE_OFFSET( addr ) (addr)
-#else
- #define CODE_PAGE( addr ) (s.code_map [NES_CPU_PAGE( addr )])
- #define CODE_OFFSET( addr ) NES_CPU_OFFSET( addr )
-#endif
-#define READ_CODE( addr ) (CODE_PAGE( addr ) [CODE_OFFSET( addr )])
-
-// Stack
-#define SET_SP( v ) (sp = ((v) + 1) | 0x100)
-#define GET_SP() ((sp - 1) & 0xFF)
-#define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100)
-
-// 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 */
-
-// Flags with hex value for clarity when used as mask.
-// Stored in indicated variable during emulation.
-int const n80 = 0x80; // nz
-int const v40 = 0x40; // flags
-int const r20 = 0x20;
-int const b10 = 0x10;
-int const d08 = 0x08; // flags
-int const i04 = 0x04; // flags
-int const z02 = 0x02; // nz
-int const c01 = 0x01; // c
-
-#define IS_NEG (nz & 0x8080)
-
-#define GET_FLAGS( out ) \
-{\
- out = flags & (v40 | d08 | i04);\
- out += ((nz >> 8) | nz) & n80;\
- out += c >> 8 & c01;\
- if ( !BYTE( nz ) )\
- out += z02;\
-}
-
-#define SET_FLAGS( in ) \
-{\
- flags = in & (v40 | d08 | i04);\
- c = nz = in << 8;\
- nz += ~in & z02;\
-}
-
-{
- int const time_offset = 0;
-
- // Local state
- struct cpu_state_t s;
- #ifdef FLAT_MEM
- s.base = cpu->cpu_state_.base;
- #else
- s = cpu->cpu_state_;
- #endif
- cpu->cpu_state = &s;
- int s_time = cpu->cpu_state_.time; // helps even on x86
-
- // Registers
- int pc = cpu->r.pc;
- int a = cpu->r.a;
- int x = cpu->r.x;
- int y = cpu->r.y;
- int sp;
- SET_SP( cpu->r.sp );
-
- // Flags
- int flags;
- int c; // carry set if (c & 0x100) != 0
- int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
- {
- int temp = cpu->r.flags;
- SET_FLAGS( temp );
- }
-
-loop:
-
- // Check all values
- check( (unsigned) sp - 0x100 < 0x100 );
- check( (unsigned) pc < 0x10000 );
- check( (unsigned) a < 0x100 );
- check( (unsigned) x < 0x100 );
- check( (unsigned) y < 0x100 );
-
- // Read instruction
- byte const* instr = CODE_PAGE( pc );
- int opcode;
-
- if ( CODE_OFFSET(~0) == ~0 )
- {
- opcode = instr [pc];
- pc++;
- instr += pc;
- }
- else
- {
- instr += CODE_OFFSET( pc );
- opcode = *instr++;
- pc++;
- }
-
- // local to function in case it helps optimizer
- static byte const clock_table [256] =
- {// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0
- 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1
- 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2
- 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3
- 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4
- 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5
- 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6
- 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7
- 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8
- 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9
- 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A
- 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B
- 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C
- 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D
- 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E
- 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F
- }; // 0x00 was 7 and 0x22 was 2
-
- // Update time
- if ( s_time >= 0 )
- goto out_of_time;
-
- #ifdef CPU_INSTR_HOOK
- { CPU_INSTR_HOOK( (pc-1), (&instr [-1]), a, x, y, GET_SP(), TIME() ); }
- #endif
-
- s_time += clock_table [opcode];
-
- int data;
- data = *instr;
-
- switch ( opcode )
- {
-
-// Macros
-
-#define GET_MSB() (instr [1])
-#define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB())
-#define GET_ADDR() GET_LE16( instr )
-
-#define PAGE_PENALTY( lsb ) s_time += (lsb) >> 8;
-
-#define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop;
-
-#define IND_Y( cross, out ) {\
- int temp = READ_LOW( data ) + y;\
- out = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\
- cross( temp );\
- }
-
-#define IND_X( out ) {\
- int temp = data + x;\
- out = 0x100 * READ_LOW( BYTE( temp + 1 ) ) + READ_LOW( BYTE( temp ) );\
- }
-
-#define ARITH_ADDR_MODES( op )\
-case op - 0x04: /* (ind,x) */\
- IND_X( data )\
- goto ptr##op;\
-case op + 0x0C: /* (ind),y */\
- IND_Y( PAGE_PENALTY, data )\
- goto ptr##op;\
-case op + 0x10: /* zp,X */\
- data = BYTE( data + x );\
-case op + 0x00: /* zp */\
- data = READ_LOW( data );\
- goto imm##op;\
-case op + 0x14: /* abs,Y */\
- data += y;\
- goto ind##op;\
-case op + 0x18: /* abs,X */\
- data += x;\
-ind##op:\
- PAGE_PENALTY( data );\
-case op + 0x08: /* abs */\
- ADD_PAGE( data );\
-ptr##op:\
- FLUSH_TIME();\
- data = READ_MEM( data );\
- CACHE_TIME();\
-case op + 0x04: /* imm */\
-imm##op:
-
-// TODO: more efficient way to handle negative branch that wraps PC around
-#define BRANCH( cond )\
-{\
- ++pc;\
- if ( !(cond) ) goto loop;\
- s_time++;\
- int offset = SBYTE( data );\
- s_time += (BYTE(pc) + offset) >> 8 & 1;\
- pc = WORD( pc + offset );\
- goto loop;\
-}
-
-// Often-Used
-
- case 0xB5: // LDA zp,x
- a = nz = READ_LOW( BYTE( data + x ) );
- pc++;
- goto loop;
-
- case 0xA5: // LDA zp
- a = nz = READ_LOW( data );
- pc++;
- goto loop;
-
- case 0xD0: // BNE
- BRANCH( BYTE( nz ) );
-
- case 0x20: { // JSR
- int temp = pc + 1;
- pc = GET_ADDR();
- WRITE_STACK( SP( -1 ), temp >> 8 );
- sp = SP( -2 );
- WRITE_STACK( sp, temp );
- goto loop;
- }
-
- case 0x4C: // JMP abs
- pc = GET_ADDR();
- goto loop;
-
- case 0xE8: // INX
- INC_DEC( x, 1 )
-
- case 0x10: // BPL
- BRANCH( !IS_NEG )
-
- ARITH_ADDR_MODES( 0xC5 ) // CMP
- nz = a - data;
- pc++;
- c = ~nz;
- nz &= 0xFF;
- goto loop;
-
- case 0x30: // BMI
- BRANCH( IS_NEG )
-
- case 0xF0: // BEQ
- BRANCH( !BYTE( nz ) );
-
- case 0x95: // STA zp,x
- data = BYTE( data + x );
- case 0x85: // STA zp
- pc++;
- WRITE_LOW( data, a );
- goto loop;
-
- case 0xC8: // INY
- INC_DEC( y, 1 )
-
- case 0xA8: // TAY
- y = a;
- nz = a;
- goto loop;
-
- case 0x98: // TYA
- a = y;
- nz = y;
- goto loop;
-
- case 0xAD:{// LDA abs
- int addr = GET_ADDR();
- pc += 2;
- READ_PPU( addr, a = nz );
- goto loop;
- }
-
- case 0x60: // RTS
- pc = 1 + READ_STACK( sp );
- pc += 0x100 * READ_STACK( SP( 1 ) );
- sp = SP( 2 );
- goto loop;
-
- {
- int addr;
-
- case 0x8D: // STA abs
- addr = GET_ADDR();
- pc += 2;
- if ( CAN_WRITE_FAST( addr ) )
- {
- WRITE_FAST( addr, a );
- goto loop;
- }
- sta_ptr:
- FLUSH_TIME();
- WRITE_MEM( addr, a );
- CACHE_TIME();
- goto loop;
-
- case 0x99: // STA abs,Y
- addr = y + GET_ADDR();
- pc += 2;
- if ( CAN_WRITE_FAST( addr ) )
- {
- WRITE_FAST( addr, a );
- goto loop;
- }
- goto sta_abs_x;
-
- case 0x9D: // STA abs,X (slightly more common than STA abs)
- addr = x + GET_ADDR();
- pc += 2;
- if ( CAN_WRITE_FAST( addr ) )
- {
- WRITE_FAST( addr, a );
- goto loop;
- }
- DUMMY_READ( addr, x );
- sta_abs_x:
- FLUSH_TIME();
- WRITE_MEM( addr, a );
- CACHE_TIME();
- goto loop;
-
- case 0x91: // STA (ind),Y
- #define NO_PAGE_PENALTY( lsb )
- IND_Y( NO_PAGE_PENALTY, addr )
- pc++;
- DUMMY_READ( addr, y );
- goto sta_ptr;
-
- case 0x81: // STA (ind,X)
- IND_X( addr )
- pc++;
- goto sta_ptr;
-
- }
-
- case 0xA9: // LDA #imm
- pc++;
- a = data;
- nz = data;
- goto loop;
-
- // common read instructions
- {
- int addr;
-
- case 0xA1: // LDA (ind,X)
- IND_X( addr )
- pc++;
- goto a_nz_read_addr;
-
- case 0xB1:// LDA (ind),Y
- addr = READ_LOW( data ) + y;
- PAGE_PENALTY( addr );
- addr += 0x100 * READ_LOW( BYTE( data + 1 ) );
- pc++;
- READ_FAST( addr, a = nz );
- if ( CAN_READ_FAST( addr ) )
- goto loop;
- DUMMY_READ( addr, y );
- goto a_nz_read_addr;
-
- case 0xB9: // LDA abs,Y
- PAGE_PENALTY( data + y );
- addr = GET_ADDR() + y;
- pc += 2;
- READ_FAST( addr, a = nz );
- if ( CAN_READ_FAST( addr ) )
- goto loop;
- goto a_nz_read_addr;
-
- case 0xBD: // LDA abs,X
- PAGE_PENALTY( data + x );
- addr = GET_ADDR() + x;
- pc += 2;
- READ_FAST( addr, a = nz );
- if ( CAN_READ_FAST( addr ) )
- goto loop;
- DUMMY_READ( addr, x );
- a_nz_read_addr:
- FLUSH_TIME();
- a = nz = READ_MEM( addr );
- CACHE_TIME();
- goto loop;
-
- }
-
-// Branch
-
- case 0x50: // BVC
- BRANCH( !(flags & v40) )
-
- case 0x70: // BVS
- BRANCH( flags & v40 )
-
- case 0xB0: // BCS
- BRANCH( c & 0x100 )
-
- case 0x90: // BCC
- BRANCH( !(c & 0x100) )
-
-// Load/store
-
- case 0x94: // STY zp,x
- data = BYTE( data + x );
- case 0x84: // STY zp
- pc++;
- WRITE_LOW( data, y );
- goto loop;
-
- case 0x96: // STX zp,y
- data = BYTE( data + y );
- case 0x86: // STX zp
- pc++;
- WRITE_LOW( data, x );
- goto loop;
-
- case 0xB6: // LDX zp,y
- data = BYTE( data + y );
- case 0xA6: // LDX zp
- data = READ_LOW( data );
- case 0xA2: // LDX #imm
- pc++;
- x = data;
- nz = data;
- goto loop;
-
- case 0xB4: // LDY zp,x
- data = BYTE( data + x );
- case 0xA4: // LDY zp
- data = READ_LOW( data );
- case 0xA0: // LDY #imm
- pc++;
- y = data;
- nz = data;
- goto loop;
-
- case 0xBC: // LDY abs,X
- data += x;
- PAGE_PENALTY( data );
- case 0xAC:{// LDY abs
- int addr = data + 0x100 * GET_MSB();
- pc += 2;
- FLUSH_TIME();
- y = nz = READ_MEM( addr );
- CACHE_TIME();
- goto loop;
- }
-
- case 0xBE: // LDX abs,y
- data += y;
- PAGE_PENALTY( data );
- case 0xAE:{// LDX abs
- int addr = data + 0x100 * GET_MSB();
- pc += 2;
- FLUSH_TIME();
- x = nz = READ_MEM( addr );
- CACHE_TIME();
- goto loop;
- }
-
- {
- int temp;
- case 0x8C: // STY abs
- temp = y;
- goto store_abs;
-
- case 0x8E: // STX abs
- temp = x;
- store_abs:
- {
- int addr = GET_ADDR();
- pc += 2;
- if ( CAN_WRITE_FAST( addr ) )
- {
- WRITE_FAST( addr, temp );
- goto loop;
- }
- FLUSH_TIME();
- WRITE_MEM( addr, temp );
- CACHE_TIME();
- goto loop;
- }
- }
-
-// Compare
-
- case 0xEC: {// CPX abs
- int addr = GET_ADDR();
- pc++;
- FLUSH_TIME();
- data = READ_MEM( addr );
- CACHE_TIME();
- goto cpx_data;
- }
-
- case 0xE4: // CPX zp
- data = READ_LOW( data );
- case 0xE0: // CPX #imm
- cpx_data:
- nz = x - data;
- pc++;
- c = ~nz;
- nz &= 0xFF;
- goto loop;
-
- case 0xCC:{// CPY abs
- int addr = GET_ADDR();
- pc++;
- FLUSH_TIME();
- data = READ_MEM( addr );
- CACHE_TIME();
- goto cpy_data;
- }
-
- case 0xC4: // CPY zp
- data = READ_LOW( data );
- case 0xC0: // CPY #imm
- cpy_data:
- nz = y - data;
- pc++;
- c = ~nz;
- nz &= 0xFF;
- goto loop;
-
-// Logical
-
- ARITH_ADDR_MODES( 0x25 ) // AND
- nz = (a &= data);
- pc++;
- goto loop;
-
- ARITH_ADDR_MODES( 0x45 ) // EOR
- nz = (a ^= data);
- pc++;
- goto loop;
-
- ARITH_ADDR_MODES( 0x05 ) // ORA
- nz = (a |= data);
- pc++;
- goto loop;
-
- case 0x2C:{// BIT abs
- int addr = GET_ADDR();
- pc += 2;
- READ_PPU( addr, nz );
- flags = (flags & ~v40) + (nz & v40);
- if ( a & nz )
- goto loop;
- nz <<= 8; // result must be zero, even if N bit is set
- goto loop;
- }
-
- case 0x24: // BIT zp
- nz = READ_LOW( data );
- pc++;
- flags = (flags & ~v40) + (nz & v40);
- if ( a & nz )
- goto loop; // Z should be clear, and nz must be non-zero if nz & a is
- nz <<= 8; // set Z flag without affecting N flag
- goto loop;
-
-// Add/subtract
-
- ARITH_ADDR_MODES( 0xE5 ) // SBC
- case 0xEB: // unofficial equivalent
- data ^= 0xFF;
- goto adc_imm;
-
- ARITH_ADDR_MODES( 0x65 ) // ADC
- adc_imm: {
- int carry = c >> 8 & 1;
- int ov = (a ^ 0x80) + carry + SBYTE( data );
- flags = (flags & ~v40) + (ov >> 2 & v40);
- c = nz = a + data + carry;
- pc++;
- a = BYTE( nz );
- goto loop;
- }
-
-// Shift/rotate
-
- case 0x4A: // LSR A
- c = 0;
- case 0x6A: // ROR A
- nz = c >> 1 & 0x80;
- c = a << 8;
- nz += a >> 1;
- a = nz;
- goto loop;
-
- case 0x0A: // ASL A
- nz = a << 1;
- c = nz;
- a = BYTE( nz );
- goto loop;
-
- case 0x2A: { // ROL A
- nz = a << 1;
- int temp = c >> 8 & 1;
- c = nz;
- nz += temp;
- a = BYTE( nz );
- goto loop;
- }
-
- case 0x5E: // LSR abs,X
- data += x;
- case 0x4E: // LSR abs
- c = 0;
- case 0x6E: // ROR abs
- ror_abs: {
- ADD_PAGE( data );
- FLUSH_TIME();
- int temp = READ_MEM( data );
- nz = (c >> 1 & 0x80) + (temp >> 1);
- c = temp << 8;
- goto rotate_common;
- }
-
- case 0x3E: // ROL abs,X
- data += x;
- goto rol_abs;
-
- case 0x1E: // ASL abs,X
- data += x;
- case 0x0E: // ASL abs
- c = 0;
- case 0x2E: // ROL abs
- rol_abs:
- ADD_PAGE( data );
- nz = c >> 8 & 1;
- FLUSH_TIME();
- nz += (c = READ_MEM( data ) << 1);
- rotate_common:
- pc++;
- WRITE_MEM( data, BYTE( nz ) );
- CACHE_TIME();
- goto loop;
-
- case 0x7E: // ROR abs,X
- data += x;
- goto ror_abs;
-
- case 0x76: // ROR zp,x
- data = BYTE( data + x );
- goto ror_zp;
-
- case 0x56: // LSR zp,x
- data = BYTE( data + x );
- case 0x46: // LSR zp
- c = 0;
- case 0x66: // ROR zp
- ror_zp: {
- int temp = READ_LOW( data );
- nz = (c >> 1 & 0x80) + (temp >> 1);
- c = temp << 8;
- goto write_nz_zp;
- }
-
- case 0x36: // ROL zp,x
- data = BYTE( data + x );
- goto rol_zp;
-
- case 0x16: // ASL zp,x
- data = BYTE( data + x );
- case 0x06: // ASL zp
- c = 0;
- case 0x26: // ROL zp
- rol_zp:
- nz = c >> 8 & 1;
- nz += (c = READ_LOW( data ) << 1);
- goto write_nz_zp;
-
-// Increment/decrement
-
- case 0xCA: // DEX
- INC_DEC( x, -1 )
-
- case 0x88: // DEY
- INC_DEC( y, -1 )
-
- case 0xF6: // INC zp,x
- data = BYTE( data + x );
- case 0xE6: // INC zp
- nz = 1;
- goto add_nz_zp;
-
- case 0xD6: // DEC zp,x
- data = BYTE( data + x );
- case 0xC6: // DEC zp
- nz = -1;
- add_nz_zp:
- nz += READ_LOW( data );
- write_nz_zp:
- pc++;
- WRITE_LOW( data, nz );
- goto loop;
-
- case 0xFE: // INC abs,x
- data = x + GET_ADDR();
- goto inc_ptr;
-
- case 0xEE: // INC abs
- data = GET_ADDR();
- inc_ptr:
- nz = 1;
- goto inc_common;
-
- case 0xDE: // DEC abs,x
- data = x + GET_ADDR();
- goto dec_ptr;
-
- case 0xCE: // DEC abs
- data = GET_ADDR();
- dec_ptr:
- nz = -1;
- inc_common:
- FLUSH_TIME();
- pc += 2;
- nz += READ_MEM( data );
- WRITE_MEM( data, BYTE( nz ) );
- CACHE_TIME();
- goto loop;
-
-// Transfer
-
- case 0xAA: // TAX
- x = nz = a;
- goto loop;
-
- case 0x8A: // TXA
- a = nz = x;
- goto loop;
-
- case 0x9A: // TXS
- SET_SP( x ); // verified (no flag change)
- goto loop;
-
- case 0xBA: // TSX
- x = nz = GET_SP();
- goto loop;
-
-// Stack
-
- case 0x48: // PHA
- sp = SP( -1 );
- WRITE_STACK( sp, a );
- goto loop;
-
- case 0x68: // PLA
- a = nz = READ_STACK( sp );
- sp = SP( 1 );
- goto loop;
-
- case 0x40:{// RTI
- pc = READ_STACK( SP( 1 ) );
- pc += READ_STACK( SP( 2 ) ) * 0x100;
- int temp = READ_STACK( sp );
- sp = SP( 3 );
- data = flags;
- SET_FLAGS( temp );
- cpu->r.flags = flags; // update externally-visible I flag
- int delta = s.base - cpu->irq_time;
- if ( delta <= 0 ) goto loop; // end_time < irq_time
- if ( flags & i04 ) goto loop;
- s_time += delta;
- s.base = cpu->irq_time;
- goto loop;
- }
-
- case 0x28:{// PLP
- int temp = READ_STACK( sp );
- sp = SP( 1 );
- int changed = flags ^ temp;
- SET_FLAGS( temp );
- if ( !(changed & i04) )
- goto loop; // I flag didn't change
- if ( flags & i04 )
- goto handle_sei;
- goto handle_cli;
- }
-
- case 0x08:{// PHP
- int temp;
- GET_FLAGS( temp );
- sp = SP( -1 );
- WRITE_STACK( sp, temp | (b10 | r20) );
- goto loop;
- }
-
- case 0x6C:{// JMP (ind)
- data = GET_ADDR();
- byte const* page = CODE_PAGE( data );
- pc = page [CODE_OFFSET( data )];
- data = (data & 0xFF00) + ((data + 1) & 0xFF);
- pc += page [CODE_OFFSET( data )] * 0x100;
- goto loop;
- }
-
- case 0x00: // BRK
- goto handle_brk;
-
-// Flags
-
- case 0x38: // SEC
- c = 0x100;
- goto loop;
-
- case 0x18: // CLC
- c = 0;
- goto loop;
-
- case 0xB8: // CLV
- flags &= ~v40;
- goto loop;
-
- case 0xD8: // CLD
- flags &= ~d08;
- goto loop;
-
- case 0xF8: // SED
- flags |= d08;
- goto loop;
-
- case 0x58: // CLI
- if ( !(flags & i04) )
- goto loop;
- flags &= ~i04;
- handle_cli: {
- //dprintf( "CLI at %d\n", TIME );
- cpu->r.flags = flags; // update externally-visible I flag
- int delta = s.base - cpu->irq_time;
- if ( delta <= 0 )
- {
- if ( TIME() < cpu->irq_time )
- goto loop;
- goto delayed_cli;
- }
- s.base = cpu->irq_time;
- s_time += delta;
- if ( s_time < 0 )
- goto loop;
-
- if ( delta >= s_time + 1 )
- {
- // delayed irq until after next instruction
- s.base += s_time + 1;
- s_time = -1;
- goto loop;
- }
-
- // TODO: implement
- delayed_cli:
- dprintf( "Delayed CLI not emulated\n" );
- goto loop;
- }
-
- case 0x78: // SEI
- if ( flags & i04 )
- goto loop;
- flags |= i04;
- handle_sei: {
- cpu->r.flags = flags; // update externally-visible I flag
- int delta = s.base - cpu->end_time;
- s.base = cpu->end_time;
- s_time += delta;
- if ( s_time < 0 )
- goto loop;
-
- dprintf( "Delayed SEI not emulated\n" );
- goto loop;
- }
-
-// Unofficial
-
- // SKW - skip word
- case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC:
- PAGE_PENALTY( data + x );
- case 0x0C:
- pc++;
- // SKB - skip byte
- case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64:
- case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4:
- pc++;
- goto loop;
-
- // NOP
- case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA:
- goto loop;
-
- case halt_opcode: // HLT - halt processor
- if ( pc-- > 0x10000 )
- {
- // handle wrap-around (assumes caller has put page of HLT at 0x10000)
- pc = WORD( pc );
- goto loop;
- }
- case 0x02: case 0x12: case 0x32: case 0x42: case 0x52:
- case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2:
- goto stop;
-
-// Unimplemented
-
- case 0xFF: // force 256-entry jump table for optimization purposes
- c |= 1; // compiler doesn't know that this won't affect anything
- default:
- check( (unsigned) opcode < 0x100 );
-
- #ifdef UNIMPL_INSTR
- UNIMPL_INSTR();
- #endif
-
- // At least skip over proper number of bytes instruction uses
- static unsigned char const illop_lens [8] = {
- 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0
- };
- int opcode = instr [-1];
- int len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3;
- if ( opcode == 0x9C )
- len = 2;
- pc += len;
-
- // Account for extra clock
- if ( (opcode >> 4) == 0x0B )
- {
- if ( opcode == 0xB3 )
- data = READ_LOW( data );
- if ( opcode != 0xB7 )
- PAGE_PENALTY( data + y );
- }
- goto loop;
- }
- assert( false ); // catch missing 'goto loop' or accidental 'break'
-
- int result_;
-handle_brk:
- pc++;
- result_ = b10 | 4;
-
-#ifdef CPU_DONE
-interrupt:
-#endif
- {
- s_time += 7;
-
- // Save PC and read vector
- WRITE_STACK( SP( -1 ), pc >> 8 );
- WRITE_STACK( SP( -2 ), pc );
- pc = GET_LE16( &READ_CODE( 0xFFFA ) + (result_ & 4) );
-
- // Save flags
- int temp;
- GET_FLAGS( temp );
- temp |= r20 + (result_ & b10); // B flag set for BRK
- sp = SP( -3 );
- WRITE_STACK( sp, temp );
-
- // Update I flag in externally-visible flags
- cpu->r.flags = (flags |= i04);
-
- // Update time
- int delta = s.base - cpu->end_time;
- if ( delta >= 0 )
- goto loop;
- s_time += delta;
- s.base = cpu->end_time;
- goto loop;
- }
-
-out_of_time:
- pc--;
-
- // Optional action that triggers interrupt or changes irq/end time
- #ifdef CPU_DONE
- {
- CPU_DONE( result_ );
- if ( result_ >= 0 )
- goto interrupt;
- if ( s_time < 0 )
- goto loop;
- }
- #endif
-stop:
-
- // Flush cached state
- cpu->r.pc = pc;
- cpu->r.sp = GET_SP();
- cpu->r.a = a;
- cpu->r.x = x;
- cpu->r.y = y;
-
- int temp;
- GET_FLAGS( temp );
- cpu->r.flags = temp;
-
- cpu->cpu_state_.base = s.base;
- cpu->cpu_state_.time = s_time;
- cpu->cpu_state = &cpu->cpu_state_;
-}