/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2006-2007 Adam Gashlin (hcs) * Copyright (C) 2004-2007 Shay Green (blargg) * Copyright (C) 2002 Brad Martin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ /* The CPU portion (shock!) */ #include "codeclib.h" #include "spc_codec.h" #include "spc_profiler.h" #undef check #define check assert #define READ( addr ) (SPC_read( this, addr, spc_time_ )) #define WRITE( addr, value ) (SPC_write( this, addr, value, spc_time_ )) #define READ_DP( addr ) READ( (addr) + dp ) #define WRITE_DP( addr, value ) WRITE( (addr) + dp, value ) #define READ_PROG16( addr ) GET_LE16( RAM + (addr) ) #define READ_PC( pc ) (*(pc)) #define READ_PC16( pc ) GET_LE16( pc ) #define SET_PC( n ) (pc = RAM + (n)) #define GET_PC() (pc - RAM) static unsigned char const cycle_table [0x100] = { 2,8,4,5,3,4,3,6,2,6,5,4,5,4,6,8, /* 0 */ 2,8,4,5,4,5,5,6,5,5,6,5,2,2,4,6, /* 1 */ 2,8,4,5,3,4,3,6,2,6,5,4,5,4,5,4, /* 2 */ 2,8,4,5,4,5,5,6,5,5,6,5,2,2,3,8, /* 3 */ 2,8,4,5,3,4,3,6,2,6,4,4,5,4,6,6, /* 4 */ 2,8,4,5,4,5,5,6,5,5,4,5,2,2,4,3, /* 5 */ 2,8,4,5,3,4,3,6,2,6,4,4,5,4,5,5, /* 6 */ 2,8,4,5,4,5,5,6,5,5,5,5,2,2,3,6, /* 7 */ 2,8,4,5,3,4,3,6,2,6,5,4,5,2,4,5, /* 8 */ 2,8,4,5,4,5,5,6,5,5,5,5,2,2,12,5,/* 9 */ 3,8,4,5,3,4,3,6,2,6,4,4,5,2,4,4, /* A */ 2,8,4,5,4,5,5,6,5,5,5,5,2,2,3,4, /* B */ 3,8,4,5,4,5,4,7,2,5,6,4,5,2,4,9, /* C */ 2,8,4,5,5,6,6,7,4,5,4,5,2,2,6,3, /* D */ 2,8,4,5,3,4,3,6,2,4,5,3,4,3,4,3, /* E */ 2,8,4,5,4,5,5,6,3,4,5,4,2,2,4,3 /* F */ }; #define MEM_BIT() CPU_mem_bit( this, pc, spc_time_ ) static unsigned CPU_mem_bit( THIS, uint8_t const* pc, long const spc_time_ ) ICODE_ATTR_SPC; static unsigned CPU_mem_bit( THIS, uint8_t const* pc, long const spc_time_ ) { unsigned addr = READ_PC16( pc ); unsigned t = READ( addr & 0x1FFF ) >> (addr >> 13); return (t << 8) & 0x100; } /* status flags */ enum { st_n = 0x80 }; enum { st_v = 0x40 }; enum { st_p = 0x20 }; enum { st_b = 0x10 }; enum { st_h = 0x08 }; enum { st_i = 0x04 }; enum { st_z = 0x02 }; enum { st_c = 0x01 }; #define IS_NEG (nz & 0x880) #define CALC_STATUS( out )\ {\ out = status & ~(st_n | st_z | st_c);\ out |= (c >> 8) & st_c;\ out |= (dp >> 3) & st_p;\ if ( IS_NEG ) out |= st_n;\ if ( !(nz & 0xFF) ) out |= st_z;\ } #define SET_STATUS( in )\ {\ status = in & ~(st_n | st_z | st_c | st_p);\ c = in << 8;\ nz = ((in << 4) & 0x800) | (~in & st_z);\ dp = (in << 3) & 0x100;\ } /* stack */ #define PUSH( v ) (*--sp = (uint8_t) (v)) #define PUSH16( v ) (sp -= 2, SET_LE16( sp, v )) #define POP() (*sp++) #define SET_SP( v ) (sp = RAM + 0x101 + (v)) #define GET_SP() (sp - 0x101 - RAM) long CPU_run( THIS, long start_time ) { ENTER_TIMER(cpu); register long spc_time_ = start_time; #ifdef CPU_ARM uint8_t* const ram_ = ram.ram; #undef RAM #define RAM ram_ #endif int a = this->r.a; int x = this->r.x; int y = this->r.y; uint8_t const* pc; SET_PC( this->r.pc ); uint8_t* sp; SET_SP( this->r.sp ); int status; int c; int nz; unsigned dp; { int temp = this->r.status; SET_STATUS( temp ); } goto loop; /* main loop */ cbranch_taken_loop: pc += *(int8_t const*) pc; spc_time_ += 2; inc_pc_loop: pc++; loop: check( (unsigned) GET_PC() < 0x10000 ); check( (unsigned) GET_SP() < 0x100 ); check( (unsigned) a < 0x100 ); check( (unsigned) x < 0x100 ); check( (unsigned) y < 0x100 ); unsigned opcode = *pc; int cycles = this->cycle_table [opcode]; unsigned data = *++pc; if ( (spc_time_ += cycles) > 0 ) goto out_of_time; switch ( opcode ) { /* Common instructions */ #define BRANCH( cond )\ {\ pc++;\ int offset = (int8_t) data;\ if ( cond ) {\ pc += offset;\ spc_time_ += 2;\ }\ goto loop;\ } case 0xF0: /* BEQ (most common) */ BRANCH( !(uint8_t) nz ) case 0xD0: /* BNE */ BRANCH( (uint8_t) nz ) case 0x3F: /* CALL */ PUSH16( GET_PC() + 2 ); SET_PC( READ_PC16( pc ) ); goto loop; case 0x6F: /* RET */ SET_PC( POP() ); pc += POP() * 0x100; goto loop; #define CASE( n ) case n: /* Define common address modes based on opcode for immediate mode. Execution ends with data set to the address of the operand. */ #define ADDR_MODES( op )\ CASE( op - 0x02 ) /* (X) */\ data = x + dp;\ pc--;\ goto end_##op;\ CASE( op + 0x0F ) /* (dp)+Y */\ data = READ_PROG16( data + dp ) + y;\ goto end_##op;\ CASE( op - 0x01 ) /* (dp+X) */\ data = READ_PROG16( ((uint8_t) (data + x)) + dp );\ goto end_##op;\ CASE( op + 0x0E ) /* abs+Y */\ data += y;\ goto abs_##op;\ CASE( op + 0x0D ) /* abs+X */\ data += x;\ CASE( op - 0x03 ) /* abs */\ abs_##op:\ data += 0x100 * READ_PC( ++pc );\ goto end_##op;\ CASE( op + 0x0C ) /* dp+X */\ data = (uint8_t) (data + x);\ CASE( op - 0x04 ) /* dp */\ data += dp;\ end_##op: /* 1. 8-bit Data Transmission Commands. Group I */ ADDR_MODES( 0xE8 ) /* MOV A,addr */ /*case 0xE4:*/ /* MOV a,dp (most common) */ mov_a_addr: a = nz = READ( data ); goto inc_pc_loop; case 0xBF: /* MOV A,(X)+ */ data = x + dp; x = (uint8_t) (x + 1); pc--; goto mov_a_addr; case 0xE8: /* MOV A,imm */ a = data; nz = data; goto inc_pc_loop; case 0xF9: /* MOV X,dp+Y */ data = (uint8_t) (data + y); case 0xF8: /* MOV X,dp */ data += dp; goto mov_x_addr; case 0xE9: /* MOV X,abs */ data = READ_PC16( pc ); pc++; mov_x_addr: data = READ( data ); case 0xCD: /* MOV X,imm */ x = data; nz = data; goto inc_pc_loop; case 0xFB: /* MOV Y,dp+X */ data = (uint8_t) (data + x); case 0xEB: /* MOV Y,dp */ data += dp; goto mov_y_addr; case 0xEC: /* MOV Y,abs */ data = READ_PC16( pc ); pc++; mov_y_addr: data = READ( data ); case 0x8D: /* MOV Y,imm */ y = data; nz = data; goto inc_pc_loop; /* 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2 */ ADDR_MODES( 0xC8 ) /* MOV addr,A */ WRITE( data, a ); goto inc_pc_loop; { int temp; case 0xCC: /* MOV abs,Y */ temp = y; goto mov_abs_temp; case 0xC9: /* MOV abs,X */ temp = x; mov_abs_temp: WRITE( READ_PC16( pc ), temp ); pc += 2; goto loop; } case 0xD9: /* MOV dp+Y,X */ data = (uint8_t) (data + y); case 0xD8: /* MOV dp,X */ WRITE( data + dp, x ); goto inc_pc_loop; case 0xDB: /* MOV dp+X,Y */ data = (uint8_t) (data + x); case 0xCB: /* MOV dp,Y */ WRITE( data + dp, y ); goto inc_pc_loop; case 0xFA: /* MOV dp,dp */ data = READ( data + dp ); case 0x8F: /* MOV dp,#imm */ WRITE_DP( READ_PC( ++pc ), data ); goto inc_pc_loop; /* 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3. */ case 0x7D: /* MOV A,X */ a = x; nz = x; goto loop; case 0xDD: /* MOV A,Y */ a = y; nz = y; goto loop; case 0x5D: /* MOV X,A */ x = a; nz = a; goto loop; case 0xFD: /* MOV Y,A */ y = a; nz = a; goto loop; case 0x9D: /* MOV X,SP */ x = nz = GET_SP(); goto loop; case 0xBD: /* MOV SP,X */ SET_SP( x ); goto loop; /*case 0xC6:*/ /* MOV (X),A (handled by MOV addr,A in group 2) */ case 0xAF: /* MOV (X)+,A */ WRITE_DP( x, a ); x++; goto loop; /* 5. 8-BIT LOGIC OPERATION COMMANDS */ #define LOGICAL_OP( op, func )\ ADDR_MODES( op ) /* addr */\ data = READ( data );\ case op: /* imm */\ nz = a func##= data;\ goto inc_pc_loop;\ { unsigned addr;\ case op + 0x11: /* X,Y */\ data = READ_DP( y );\ addr = x + dp;\ pc--;\ goto addr_##op;\ case op + 0x01: /* dp,dp */\ data = READ_DP( data );\ case op + 0x10: /*dp,imm*/\ addr = READ_PC( ++pc ) + dp;\ addr_##op:\ nz = data func READ( addr );\ WRITE( addr, nz );\ goto inc_pc_loop;\ } LOGICAL_OP( 0x28, & ); /* AND */ LOGICAL_OP( 0x08, | ); /* OR */ LOGICAL_OP( 0x48, ^ ); /* EOR */ /* 4. 8-BIT ARITHMETIC OPERATION COMMANDS */ ADDR_MODES( 0x68 ) /* CMP addr */ data = READ( data ); case 0x68: /* CMP imm */ nz = a - data; c = ~nz; nz &= 0xFF; goto inc_pc_loop; case 0x79: /* CMP (X),(Y) */ data = READ_DP( x ); nz = data - READ_DP( y ); c = ~nz; nz &= 0xFF; goto loop; case 0x69: /* CMP (dp),(dp) */ data = READ_DP( data ); case 0x78: /* CMP dp,imm */ nz = READ_DP( READ_PC( ++pc ) ) - data; c = ~nz; nz &= 0xFF; goto inc_pc_loop; case 0x3E: /* CMP X,dp */ data += dp; goto cmp_x_addr; case 0x1E: /* CMP X,abs */ data = READ_PC16( pc ); pc++; cmp_x_addr: data = READ( data ); case 0xC8: /* CMP X,imm */ nz = x - data; c = ~nz; nz &= 0xFF; goto inc_pc_loop; case 0x7E: /* CMP Y,dp */ data += dp; goto cmp_y_addr; case 0x5E: /* CMP Y,abs */ data = READ_PC16( pc ); pc++; cmp_y_addr: data = READ( data ); case 0xAD: /* CMP Y,imm */ nz = y - data; c = ~nz; nz &= 0xFF; goto inc_pc_loop; { int addr; case 0xB9: /* SBC (x),(y) */ case 0x99: /* ADC (x),(y) */ pc--; /* compensate for inc later */ data = READ_DP( x ); addr = y + dp; goto adc_addr; case 0xA9: /* SBC dp,dp */ case 0x89: /* ADC dp,dp */ data = READ_DP( data ); case 0xB8: /* SBC dp,imm */ case 0x98: /* ADC dp,imm */ addr = READ_PC( ++pc ) + dp; adc_addr: nz = READ( addr ); goto adc_data; /* catch ADC and SBC together, then decode later based on operand */ #undef CASE #define CASE( n ) case n: case (n) + 0x20: ADDR_MODES( 0x88 ) /* ADC/SBC addr */ data = READ( data ); case 0xA8: /* SBC imm */ case 0x88: /* ADC imm */ addr = -1; /* A */ nz = a; adc_data: { if ( opcode & 0x20 ) data ^= 0xFF; /* SBC */ int carry = (c >> 8) & 1; int ov = (nz ^ 0x80) + carry + (int8_t) data; /* sign-extend */ int hc = (nz & 15) + carry; c = nz += data + carry; hc = (nz & 15) - hc; status = (status & ~(st_v | st_h)) | ((ov >> 2) & st_v) | ((hc >> 1) & st_h); if ( addr < 0 ) { a = (uint8_t) nz; goto inc_pc_loop; } WRITE( addr, (uint8_t) nz ); goto inc_pc_loop; } } /* 6. ADDITION & SUBTRACTION COMMANDS */ #define INC_DEC_REG( reg, n )\ nz = reg + n;\ reg = (uint8_t) nz;\ goto loop; case 0xBC: INC_DEC_REG( a, 1 ) /* INC A */ case 0x3D: INC_DEC_REG( x, 1 ) /* INC X */ case 0xFC: INC_DEC_REG( y, 1 ) /* INC Y */ case 0x9C: INC_DEC_REG( a, -1 ) /* DEC A */ case 0x1D: INC_DEC_REG( x, -1 ) /* DEC X */ case 0xDC: INC_DEC_REG( y, -1 ) /* DEC Y */ case 0x9B: /* DEC dp+X */ case 0xBB: /* INC dp+X */ data = (uint8_t) (data + x); case 0x8B: /* DEC dp */ case 0xAB: /* INC dp */ data += dp; goto inc_abs; case 0x8C: /* DEC abs */ case 0xAC: /* INC abs */ data = READ_PC16( pc ); pc++; inc_abs: nz = ((opcode >> 4) & 2) - 1; nz += READ( data ); WRITE( data, (uint8_t) nz ); goto inc_pc_loop; /* 7. SHIFT, ROTATION COMMANDS */ case 0x5C: /* LSR A */ c = 0; case 0x7C:{/* ROR A */ nz = ((c >> 1) & 0x80) | (a >> 1); c = a << 8; a = nz; goto loop; } case 0x1C: /* ASL A */ c = 0; case 0x3C:{/* ROL A */ int temp = (c >> 8) & 1; c = a << 1; nz = c | temp; a = (uint8_t) nz; goto loop; } case 0x0B: /* ASL dp */ c = 0; data += dp; goto rol_mem; case 0x1B: /* ASL dp+X */ c = 0; case 0x3B: /* ROL dp+X */ data = (uint8_t) (data + x); case 0x2B: /* ROL dp */ data += dp; goto rol_mem; case 0x0C: /* ASL abs */ c = 0; case 0x2C: /* ROL abs */ data = READ_PC16( pc ); pc++; rol_mem: nz = (c >> 8) & 1; nz |= (c = READ( data ) << 1); WRITE( data, (uint8_t) nz ); goto inc_pc_loop; case 0x4B: /* LSR dp */ c = 0; data += dp; goto ror_mem; case 0x5B: /* LSR dp+X */ c = 0; case 0x7B: /* ROR dp+X */ data = (uint8_t) (data + x); case 0x6B: /* ROR dp */ data += dp; goto ror_mem; case 0x4C: /* LSR abs */ c = 0; case 0x6C: /* ROR abs */ data = READ_PC16( pc ); pc++; ror_mem: { int temp = READ( data ); nz = ((c >> 1) & 0x80) | (temp >> 1); c = temp << 8; WRITE( data, nz ); goto inc_pc_loop; } case 0x9F: /* XCN */ nz = a = (a >> 4) | (uint8_t) (a << 4); goto loop; /* 8. 16-BIT TRANSMISION COMMANDS */ case 0xBA: /* MOVW YA,dp */ a = READ_DP( data ); nz = (a & 0x7F) | (a >> 1); y = READ_DP( (uint8_t) (data + 1) ); nz |= y; goto inc_pc_loop; case 0xDA: /* MOVW dp,YA */ WRITE_DP( data, a ); WRITE_DP( (uint8_t) (data + 1), y ); goto inc_pc_loop; /* 9. 16-BIT OPERATION COMMANDS */ case 0x3A: /* INCW dp */ case 0x1A:{/* DECW dp */ data += dp; /* low byte */ int temp = READ( data ); temp += ((opcode >> 4) & 2) - 1; /* +1 for INCW, -1 for DECW */ nz = ((temp >> 1) | temp) & 0x7F; WRITE( data, (uint8_t) temp ); /* high byte */ data = ((uint8_t) (data + 1)) + dp; temp >>= 8; temp = (uint8_t) (temp + READ( data )); nz |= temp; WRITE( data, temp ); goto inc_pc_loop; } case 0x9A: /* SUBW YA,dp */ case 0x7A: /* ADDW YA,dp */ { /* read 16-bit addend */ int temp = READ_DP( data ); int sign = READ_DP( (uint8_t) (data + 1) ); temp += 0x100 * sign; status &= ~(st_v | st_h); /* to do: fix half-carry for SUBW (it's probably wrong) */ /* for SUBW, negate and truncate to 16 bits */ if ( opcode & 0x80 ) { temp = (temp ^ 0xFFFF) + 1; sign = temp >> 8; } /* add low byte (A) */ temp += a; a = (uint8_t) temp; nz = (temp | (temp >> 1)) & 0x7F; /* add high byte (Y) */ temp >>= 8; c = y + temp; nz = (nz | c) & 0xFF; /* half-carry (temporary avoids CodeWarrior optimizer bug) */ unsigned hc = (c & 15) - (y & 15); status |= (hc >> 4) & st_h; /* overflow if sign of YA changed when previous sign and addend sign were same */ status |= (((c ^ y) & ~(y ^ sign)) >> 1) & st_v; y = (uint8_t) c; goto inc_pc_loop; } case 0x5A: { /* CMPW YA,dp */ int temp = a - READ_DP( data ); nz = ((temp >> 1) | temp) & 0x7F; temp = y + (temp >> 8); temp -= READ_DP( (uint8_t) (data + 1) ); nz |= temp; c = ~temp; nz &= 0xFF; goto inc_pc_loop; } /* 10. MULTIPLICATION & DIVISON COMMANDS */ case 0xCF: { /* MUL YA */ unsigned temp = y * a; a = (uint8_t) temp; nz = ((temp >> 1) | temp) & 0x7F; y = temp >> 8; nz |= y; goto loop; } case 0x9E: /* DIV YA,X */ { /* behavior based on SPC CPU tests */ status &= ~(st_h | st_v); if ( (y & 15) >= (x & 15) ) status |= st_h; if ( y >= x ) status |= st_v; unsigned ya = y * 0x100 + a; if ( y < x * 2 ) { a = ya / x; y = ya - a * x; } else { a = 255 - (ya - x * 0x200) / (256 - x); y = x + (ya - x * 0x200) % (256 - x); } nz = (uint8_t) a; a = (uint8_t) a; goto loop; } /* 11. DECIMAL COMPENSATION COMMANDS */ /* seem unused */ /* case 0xDF: */ /* DAA */ /* case 0xBE: */ /* DAS */ /* 12. BRANCHING COMMANDS */ case 0x2F: /* BRA rel */ pc += (int8_t) data; goto inc_pc_loop; case 0x30: /* BMI */ BRANCH( IS_NEG ) case 0x10: /* BPL */ BRANCH( !IS_NEG ) case 0xB0: /* BCS */ BRANCH( c & 0x100 ) case 0x90: /* BCC */ BRANCH( !(c & 0x100) ) case 0x70: /* BVS */ BRANCH( status & st_v ) case 0x50: /* BVC */ BRANCH( !(status & st_v) ) case 0x03: /* BBS dp.bit,rel */ case 0x23: case 0x43: case 0x63: case 0x83: case 0xA3: case 0xC3: case 0xE3: pc++; if ( (READ_DP( data ) >> (opcode >> 5)) & 1 ) goto cbranch_taken_loop; goto inc_pc_loop; case 0x13: /* BBC dp.bit,rel */ case 0x33: case 0x53: case 0x73: case 0x93: case 0xB3: case 0xD3: case 0xF3: pc++; if ( !((READ_DP( data ) >> (opcode >> 5)) & 1) ) goto cbranch_taken_loop; goto inc_pc_loop; case 0xDE: /* CBNE dp+X,rel */ data = (uint8_t) (data + x); /* fall through */ case 0x2E: /* CBNE dp,rel */ pc++; if ( READ_DP( data ) != a ) goto cbranch_taken_loop; goto inc_pc_loop; case 0xFE: /* DBNZ Y,rel */ y = (uint8_t) (y - 1); BRANCH( y ) case 0x6E: { /* DBNZ dp,rel */ pc++; unsigned temp = READ_DP( data ) - 1; WRITE_DP( (uint8_t) data, (uint8_t) temp ); if ( temp ) goto cbranch_taken_loop; goto inc_pc_loop; } case 0x1F: /* JMP (abs+X) */ SET_PC( READ_PC16( pc ) + x ); /* fall through */ case 0x5F: /* JMP abs */ SET_PC( READ_PC16( pc ) ); goto loop; /* 13. SUB-ROUTINE CALL RETURN COMMANDS */ case 0x0F:{/* BRK */ check( 0 ); /* untested */ PUSH16( GET_PC() + 1 ); SET_PC( READ_PROG16( 0xFFDE ) ); /* vector address verified */ int temp; CALC_STATUS( temp ); PUSH( temp ); status = (status | st_b) & ~st_i; goto loop; } case 0x4F: /* PCALL offset */ PUSH16( GET_PC() + 1 ); SET_PC( 0xFF00 + data ); goto loop; case 0x01: /* TCALL n */ case 0x11: case 0x21: case 0x31: case 0x41: case 0x51: case 0x61: case 0x71: case 0x81: case 0x91: case 0xA1: case 0xB1: case 0xC1: case 0xD1: case 0xE1: case 0xF1: PUSH16( GET_PC() ); SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) ); goto loop; /* 14. STACK OPERATION COMMANDS */ { int temp; case 0x7F: /* RET1 */ temp = POP(); SET_PC( POP() ); pc += POP() << 8; goto set_status; case 0x8E: /* POP PSW */ temp = POP(); set_status: SET_STATUS( temp ); goto loop; } case 0x0D: { /* PUSH PSW */ int temp; CALC_STATUS( temp ); PUSH( temp ); goto loop; } case 0x2D: /* PUSH A */ PUSH( a ); goto loop; case 0x4D: /* PUSH X */ PUSH( x ); goto loop; case 0x6D: /* PUSH Y */ PUSH( y ); goto loop; case 0xAE: /* POP A */ a = POP(); goto loop; case 0xCE: /* POP X */ x = POP(); goto loop; case 0xEE: /* POP Y */ y = POP(); goto loop; /* 15. BIT OPERATION COMMANDS */ case 0x02: /* SET1 */ case 0x22: case 0x42: case 0x62: case 0x82: case 0xA2: case 0xC2: case 0xE2: case 0x12: /* CLR1 */ case 0x32: case 0x52: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2: { data += dp; int bit = 1 << (opcode >> 5); int mask = ~bit; if ( opcode & 0x10 ) bit = 0; WRITE( data, (READ( data ) & mask) | bit ); goto inc_pc_loop; } case 0x0E: /* TSET1 abs */ case 0x4E:{/* TCLR1 abs */ data = READ_PC16( pc ); pc += 2; unsigned temp = READ( data ); nz = temp & a; temp &= ~a; if ( !(opcode & 0x40) ) temp |= a; WRITE( data, temp ); goto loop; } case 0x4A: /* AND1 C,mem.bit */ c &= MEM_BIT(); pc += 2; goto loop; case 0x6A: /* AND1 C,/mem.bit */ check( 0 ); /* untested */ c &= ~MEM_BIT(); pc += 2; goto loop; case 0x0A: /* OR1 C,mem.bit */ check( 0 ); /* untested */ c |= MEM_BIT(); pc += 2; goto loop; case 0x2A: /* OR1 C,/mem.bit */ check( 0 ); /* untested */ c |= ~MEM_BIT(); pc += 2; goto loop; case 0x8A: /* EOR1 C,mem.bit */ c ^= MEM_BIT(); pc += 2; goto loop; case 0xEA: { /* NOT1 mem.bit */ data = READ_PC16( pc ); pc += 2; unsigned temp = READ( data & 0x1FFF ); temp ^= 1 << (data >> 13); WRITE( data & 0x1FFF, temp ); goto loop; } case 0xCA: { /* MOV1 mem.bit,C */ data = READ_PC16( pc ); pc += 2; unsigned temp = READ( data & 0x1FFF ); unsigned bit = data >> 13; temp = (temp & ~(1 << bit)) | (((c >> 8) & 1) << bit); WRITE( data & 0x1FFF, temp ); goto loop; } case 0xAA: /* MOV1 C,mem.bit */ c = MEM_BIT(); pc += 2; goto loop; /* 16. PROGRAM STATUS FLAG OPERATION COMMANDS */ case 0x60: /* CLRC */ c = 0; goto loop; case 0x80: /* SETC */ c = ~0; goto loop; case 0xED: /* NOTC */ c ^= 0x100; goto loop; case 0xE0: /* CLRV */ status &= ~(st_v | st_h); goto loop; case 0x20: /* CLRP */ dp = 0; goto loop; case 0x40: /* SETP */ dp = 0x100; goto loop; case 0xA0: /* EI */ check( 0 ); /* untested */ status |= st_i; goto loop; case 0xC0: /* DI */ check( 0 ); /* untested */ status &= ~st_i; goto loop; /* 17. OTHER COMMANDS */ case 0x00: /* NOP */ goto loop; /*case 0xEF:*/ /* SLEEP */ /*case 0xFF:*/ /* STOP */ case 0xFF: c |= 1; /* force switch table to have 256 entries, hopefully helping optimizer */ } /* switch */ /* unhandled instructions fall out of switch so emulator can catch them */ out_of_time: /* undo partial execution of opcode */ spc_time_ -= this->cycle_table [*--pc]; { int temp; CALC_STATUS( temp ); this->r.status = (uint8_t) temp; } this->r.pc = GET_PC(); this->r.sp = (uint8_t) GET_SP(); this->r.a = (uint8_t) a; this->r.x = (uint8_t) x; this->r.y = (uint8_t) y; EXIT_TIMER(cpu); return spc_time_; } void CPU_Init( THIS ) { ci->memcpy( this->cycle_table, cycle_table, sizeof cycle_table ); }