Mercurial > spc_convert
view snes_spc/SPC_CPU.h @ 0:e38dacceb958
initial import
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 21 Oct 2011 05:53:11 -0700 |
parents | |
children |
line wrap: on
line source
1 // snes_spc 0.9.0. http://www.slack.net/~ant/3 /* Copyright (C) 2004-2007 Shay Green. This module is free software; you4 can redistribute it and/or modify it under the terms of the GNU Lesser5 General Public License as published by the Free Software Foundation; either6 version 2.1 of the License, or (at your option) any later version. This7 module is distributed in the hope that it will be useful, but WITHOUT ANY8 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS9 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more10 details. You should have received a copy of the GNU Lesser General Public11 License along with this module; if not, write to the Free Software Foundation,12 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */14 //// Memory access16 #if SPC_MORE_ACCURACY17 #define SUSPICIOUS_OPCODE( name ) ((void) 0)18 #else19 #define SUSPICIOUS_OPCODE( name ) dprintf( "SPC: suspicious opcode: " name "\n" )20 #endif22 #define CPU_READ( time, offset, addr )\23 cpu_read( addr, time + offset )25 #define CPU_WRITE( time, offset, addr, data )\26 cpu_write( data, addr, time + offset )28 #if SPC_MORE_ACCURACY29 #define CPU_READ_TIMER( time, offset, addr, out )\30 { out = CPU_READ( time, offset, addr ); }32 #else33 // timers are by far the most common thing read from dp34 #define CPU_READ_TIMER( time, offset, addr_, out )\35 {\36 rel_time_t adj_time = time + offset;\37 int dp_addr = addr_;\38 int ti = dp_addr - (r_t0out + 0xF0);\39 if ( (unsigned) ti < timer_count )\40 {\41 Timer* t = &m.timers [ti];\42 if ( adj_time >= t->next_time )\43 t = run_timer_( t, adj_time );\44 out = t->counter;\45 t->counter = 0;\46 }\47 else\48 {\49 out = ram [dp_addr];\50 int i = dp_addr - 0xF0;\51 if ( (unsigned) i < 0x10 )\52 out = cpu_read_smp_reg( i, adj_time );\53 }\54 }55 #endif57 #define TIME_ADJ( n ) (n)59 #define READ_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), (addr), out )60 #define READ( time, addr ) CPU_READ ( rel_time, TIME_ADJ(time), (addr) )61 #define WRITE( time, addr, data ) CPU_WRITE( rel_time, TIME_ADJ(time), (addr), (data) )63 #define DP_ADDR( addr ) (dp + (addr))65 #define READ_DP_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), DP_ADDR( addr ), out )66 #define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) )67 #define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data )69 #define READ_PROG16( addr ) GET_LE16( ram + (addr) )71 #define SET_PC( n ) (pc = ram + (n))72 #define GET_PC() (pc - ram)73 #define READ_PC( pc ) (*(pc))74 #define READ_PC16( pc ) GET_LE16( pc )76 // TODO: remove non-wrapping versions?77 #define SPC_NO_SP_WRAPAROUND 079 #define SET_SP( v ) (sp = ram + 0x101 + (v))80 #define GET_SP() (sp - 0x101 - ram)82 #if SPC_NO_SP_WRAPAROUND83 #define PUSH16( v ) (sp -= 2, SET_LE16( sp, v ))84 #define PUSH( v ) (void) (*--sp = (uint8_t) (v))85 #define POP( out ) (void) ((out) = *sp++)87 #else88 #define PUSH16( data )\89 {\90 int addr = (sp -= 2) - ram;\91 if ( addr > 0x100 )\92 {\93 SET_LE16( sp, data );\94 }\95 else\96 {\97 ram [(uint8_t) addr + 0x100] = (uint8_t) data;\98 sp [1] = (uint8_t) (data >> 8);\99 sp += 0x100;\100 }\101 }103 #define PUSH( data )\104 {\105 *--sp = (uint8_t) (data);\106 if ( sp - ram == 0x100 )\107 sp += 0x100;\108 }110 #define POP( out )\111 {\112 out = *sp++;\113 if ( sp - ram == 0x201 )\114 {\115 out = sp [-0x101];\116 sp -= 0x100;\117 }\118 }120 #endif122 #define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel )124 unsigned SNES_SPC::CPU_mem_bit( uint8_t const* pc, rel_time_t rel_time )125 {126 unsigned addr = READ_PC16( pc );127 unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13);128 return t << 8 & 0x100;129 }131 //// Status flag handling133 // Hex value in name to clarify code and bit shifting.134 // Flag stored in indicated variable during emulation135 int const n80 = 0x80; // nz136 int const v40 = 0x40; // psw137 int const p20 = 0x20; // dp138 int const b10 = 0x10; // psw139 int const h08 = 0x08; // psw140 int const i04 = 0x04; // psw141 int const z02 = 0x02; // nz142 int const c01 = 0x01; // c144 int const nz_neg_mask = 0x880; // either bit set indicates N flag set146 #define GET_PSW( out )\147 {\148 out = psw & ~(n80 | p20 | z02 | c01);\149 out |= c >> 8 & c01;\150 out |= dp >> 3 & p20;\151 out |= ((nz >> 4) | nz) & n80;\152 if ( !(uint8_t) nz ) out |= z02;\153 }155 #define SET_PSW( in )\156 {\157 psw = in;\158 c = in << 8;\159 dp = in << 3 & 0x100;\160 nz = (in << 4 & 0x800) | (~in & z02);\161 }163 SPC_CPU_RUN_FUNC164 {165 uint8_t* const ram = RAM;166 int a = m.cpu_regs.a;167 int x = m.cpu_regs.x;168 int y = m.cpu_regs.y;169 uint8_t const* pc;170 uint8_t* sp;171 int psw;172 int c;173 int nz;174 int dp;176 SET_PC( m.cpu_regs.pc );177 SET_SP( m.cpu_regs.sp );178 SET_PSW( m.cpu_regs.psw );180 goto loop;183 // Main loop185 cbranch_taken_loop:186 pc += *(BOOST::int8_t const*) pc;187 inc_pc_loop:188 pc++;189 loop:190 {191 unsigned opcode;192 unsigned data;194 check( (unsigned) a < 0x100 );195 check( (unsigned) x < 0x100 );196 check( (unsigned) y < 0x100 );198 opcode = *pc;199 if ( (rel_time += m.cycle_table [opcode]) > 0 )200 goto out_of_time;202 #ifdef SPC_CPU_OPCODE_HOOK203 SPC_CPU_OPCODE_HOOK( GET_PC(), opcode );204 #endif205 /*206 //SUB_CASE_COUNTER( 1 );207 #define PROFILE_TIMER_LOOP( op, addr, len )\208 if ( opcode == op )\209 {\210 int cond = (unsigned) ((addr) - 0xFD) < 3 &&\211 pc [len] == 0xF0 && pc [len+1] == 0xFE - len;\212 SUB_CASE_COUNTER( op && cond );\213 }215 PROFILE_TIMER_LOOP( 0xEC, GET_LE16( pc + 1 ), 3 );216 PROFILE_TIMER_LOOP( 0xEB, pc [1], 2 );217 PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 );218 */220 // TODO: if PC is at end of memory, this will get wrong operand (very obscure)221 data = *++pc;222 switch ( opcode )223 {225 // Common instructions227 #define BRANCH( cond )\228 {\229 pc++;\230 pc += (BOOST::int8_t) data;\231 if ( cond )\232 goto loop;\233 pc -= (BOOST::int8_t) data;\234 rel_time -= 2;\235 goto loop;\236 }238 case 0xF0: // BEQ239 BRANCH( !(uint8_t) nz ) // 89% taken241 case 0xD0: // BNE242 BRANCH( (uint8_t) nz )244 case 0x3F:{// CALL245 int old_addr = GET_PC() + 2;246 SET_PC( READ_PC16( pc ) );247 PUSH16( old_addr );248 goto loop;249 }251 case 0x6F:// RET252 #if SPC_NO_SP_WRAPAROUND253 {254 SET_PC( GET_LE16( sp ) );255 sp += 2;256 }257 #else258 {259 int addr = sp - ram;260 SET_PC( GET_LE16( sp ) );261 sp += 2;262 if ( addr < 0x1FF )263 goto loop;265 SET_PC( sp [-0x101] * 0x100 + ram [(uint8_t) addr + 0x100] );266 sp -= 0x100;267 }268 #endif269 goto loop;271 case 0xE4: // MOV a,dp272 ++pc;273 // 80% from timer274 READ_DP_TIMER( 0, data, a = nz );275 goto loop;277 case 0xFA:{// MOV dp,dp278 int temp;279 READ_DP_TIMER( -2, data, temp );280 data = temp + no_read_before_write ;281 }282 // fall through283 case 0x8F:{// MOV dp,#imm284 int temp = READ_PC( pc + 1 );285 pc += 2;287 #if !SPC_MORE_ACCURACY288 {289 int i = dp + temp;290 ram [i] = (uint8_t) data;291 i -= 0xF0;292 if ( (unsigned) i < 0x10 ) // 76%293 {294 REGS [i] = (uint8_t) data;296 // Registers other than $F2 and $F4-$F7297 //if ( i != 2 && i != 4 && i != 5 && i != 6 && i != 7 )298 if ( ((~0x2F00 << (bits_in_int - 16)) << i) < 0 ) // 12%299 cpu_write_smp_reg( data, rel_time, i );300 }301 }302 #else303 WRITE_DP( 0, temp, data );304 #endif305 goto loop;306 }308 case 0xC4: // MOV dp,a309 ++pc;310 #if !SPC_MORE_ACCURACY311 {312 int i = dp + data;313 ram [i] = (uint8_t) a;314 i -= 0xF0;315 if ( (unsigned) i < 0x10 ) // 39%316 {317 unsigned sel = i - 2;318 REGS [i] = (uint8_t) a;320 if ( sel == 1 ) // 51% $F3321 dsp_write( a, rel_time );322 else if ( sel > 1 ) // 1% not $F2 or $F3323 cpu_write_smp_reg_( a, rel_time, i );324 }325 }326 #else327 WRITE_DP( 0, data, a );328 #endif329 goto loop;331 #define CASE( n ) case n:333 // Define common address modes based on opcode for immediate mode. Execution334 // ends with data set to the address of the operand.335 #define ADDR_MODES_( op )\336 CASE( op - 0x02 ) /* (X) */\337 data = x + dp;\338 pc--;\339 goto end_##op;\340 CASE( op + 0x0F ) /* (dp)+Y */\341 data = READ_PROG16( data + dp ) + y;\342 goto end_##op;\343 CASE( op - 0x01 ) /* (dp+X) */\344 data = READ_PROG16( ((uint8_t) (data + x)) + dp );\345 goto end_##op;\346 CASE( op + 0x0E ) /* abs+Y */\347 data += y;\348 goto abs_##op;\349 CASE( op + 0x0D ) /* abs+X */\350 data += x;\351 CASE( op - 0x03 ) /* abs */\352 abs_##op:\353 data += 0x100 * READ_PC( ++pc );\354 goto end_##op;\355 CASE( op + 0x0C ) /* dp+X */\356 data = (uint8_t) (data + x);358 #define ADDR_MODES_NO_DP( op )\359 ADDR_MODES_( op )\360 data += dp;\361 end_##op:363 #define ADDR_MODES( op )\364 ADDR_MODES_( op )\365 CASE( op - 0x04 ) /* dp */\366 data += dp;\367 end_##op:369 // 1. 8-bit Data Transmission Commands. Group I371 ADDR_MODES_NO_DP( 0xE8 ) // MOV A,addr372 a = nz = READ( 0, data );373 goto inc_pc_loop;375 case 0xBF:{// MOV A,(X)+376 int temp = x + dp;377 x = (uint8_t) (x + 1);378 a = nz = READ( -1, temp );379 goto loop;380 }382 case 0xE8: // MOV A,imm383 a = data;384 nz = data;385 goto inc_pc_loop;387 case 0xF9: // MOV X,dp+Y388 data = (uint8_t) (data + y);389 case 0xF8: // MOV X,dp390 READ_DP_TIMER( 0, data, x = nz );391 goto inc_pc_loop;393 case 0xE9: // MOV X,abs394 data = READ_PC16( pc );395 ++pc;396 data = READ( 0, data );397 case 0xCD: // MOV X,imm398 x = data;399 nz = data;400 goto inc_pc_loop;402 case 0xFB: // MOV Y,dp+X403 data = (uint8_t) (data + x);404 case 0xEB: // MOV Y,dp405 // 70% from timer406 pc++;407 READ_DP_TIMER( 0, data, y = nz );408 goto loop;410 case 0xEC:{// MOV Y,abs411 int temp = READ_PC16( pc );412 pc += 2;413 READ_TIMER( 0, temp, y = nz );414 //y = nz = READ( 0, temp );415 goto loop;416 }418 case 0x8D: // MOV Y,imm419 y = data;420 nz = data;421 goto inc_pc_loop;423 // 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2425 ADDR_MODES_NO_DP( 0xC8 ) // MOV addr,A426 WRITE( 0, data, a );427 goto inc_pc_loop;429 {430 int temp;431 case 0xCC: // MOV abs,Y432 temp = y;433 goto mov_abs_temp;434 case 0xC9: // MOV abs,X435 temp = x;436 mov_abs_temp:437 WRITE( 0, READ_PC16( pc ), temp );438 pc += 2;439 goto loop;440 }442 case 0xD9: // MOV dp+Y,X443 data = (uint8_t) (data + y);444 case 0xD8: // MOV dp,X445 WRITE( 0, data + dp, x );446 goto inc_pc_loop;448 case 0xDB: // MOV dp+X,Y449 data = (uint8_t) (data + x);450 case 0xCB: // MOV dp,Y451 WRITE( 0, data + dp, y );452 goto inc_pc_loop;454 // 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3.456 case 0x7D: // MOV A,X457 a = x;458 nz = x;459 goto loop;461 case 0xDD: // MOV A,Y462 a = y;463 nz = y;464 goto loop;466 case 0x5D: // MOV X,A467 x = a;468 nz = a;469 goto loop;471 case 0xFD: // MOV Y,A472 y = a;473 nz = a;474 goto loop;476 case 0x9D: // MOV X,SP477 x = nz = GET_SP();478 goto loop;480 case 0xBD: // MOV SP,X481 SET_SP( x );482 goto loop;484 //case 0xC6: // MOV (X),A (handled by MOV addr,A in group 2)486 case 0xAF: // MOV (X)+,A487 WRITE_DP( 0, x, a + no_read_before_write );488 x++;489 goto loop;491 // 5. 8-BIT LOGIC OPERATION COMMANDS493 #define LOGICAL_OP( op, func )\494 ADDR_MODES( op ) /* addr */\495 data = READ( 0, data );\496 case op: /* imm */\497 nz = a func##= data;\498 goto inc_pc_loop;\499 { unsigned addr;\500 case op + 0x11: /* X,Y */\501 data = READ_DP( -2, y );\502 addr = x + dp;\503 goto addr_##op;\504 case op + 0x01: /* dp,dp */\505 data = READ_DP( -3, data );\506 case op + 0x10:{/*dp,imm*/\507 uint8_t const* addr2 = pc + 1;\508 pc += 2;\509 addr = READ_PC( addr2 ) + dp;\510 }\511 addr_##op:\512 nz = data func READ( -1, addr );\513 WRITE( 0, addr, nz );\514 goto loop;\515 }517 LOGICAL_OP( 0x28, & ); // AND519 LOGICAL_OP( 0x08, | ); // OR521 LOGICAL_OP( 0x48, ^ ); // EOR523 // 4. 8-BIT ARITHMETIC OPERATION COMMANDS525 ADDR_MODES( 0x68 ) // CMP addr526 data = READ( 0, data );527 case 0x68: // CMP imm528 nz = a - data;529 c = ~nz;530 nz &= 0xFF;531 goto inc_pc_loop;533 case 0x79: // CMP (X),(Y)534 data = READ_DP( -2, y );535 nz = READ_DP( -1, x ) - data;536 c = ~nz;537 nz &= 0xFF;538 goto loop;540 case 0x69: // CMP dp,dp541 data = READ_DP( -3, data );542 case 0x78: // CMP dp,imm543 nz = READ_DP( -1, READ_PC( ++pc ) ) - data;544 c = ~nz;545 nz &= 0xFF;546 goto inc_pc_loop;548 case 0x3E: // CMP X,dp549 data += dp;550 goto cmp_x_addr;551 case 0x1E: // CMP X,abs552 data = READ_PC16( pc );553 pc++;554 cmp_x_addr:555 data = READ( 0, data );556 case 0xC8: // CMP X,imm557 nz = x - data;558 c = ~nz;559 nz &= 0xFF;560 goto inc_pc_loop;562 case 0x7E: // CMP Y,dp563 data += dp;564 goto cmp_y_addr;565 case 0x5E: // CMP Y,abs566 data = READ_PC16( pc );567 pc++;568 cmp_y_addr:569 data = READ( 0, data );570 case 0xAD: // CMP Y,imm571 nz = y - data;572 c = ~nz;573 nz &= 0xFF;574 goto inc_pc_loop;576 {577 int addr;578 case 0xB9: // SBC (x),(y)579 case 0x99: // ADC (x),(y)580 pc--; // compensate for inc later581 data = READ_DP( -2, y );582 addr = x + dp;583 goto adc_addr;584 case 0xA9: // SBC dp,dp585 case 0x89: // ADC dp,dp586 data = READ_DP( -3, data );587 case 0xB8: // SBC dp,imm588 case 0x98: // ADC dp,imm589 addr = READ_PC( ++pc ) + dp;590 adc_addr:591 nz = READ( -1, addr );592 goto adc_data;594 // catch ADC and SBC together, then decode later based on operand595 #undef CASE596 #define CASE( n ) case n: case (n) + 0x20:597 ADDR_MODES( 0x88 ) // ADC/SBC addr598 data = READ( 0, data );599 case 0xA8: // SBC imm600 case 0x88: // ADC imm601 addr = -1; // A602 nz = a;603 adc_data: {604 int flags;605 if ( opcode >= 0xA0 ) // SBC606 data ^= 0xFF;608 flags = data ^ nz;609 nz += data + (c >> 8 & 1);610 flags ^= nz;612 psw = (psw & ~(v40 | h08)) |613 (flags >> 1 & h08) |614 ((flags + 0x80) >> 2 & v40);615 c = nz;616 if ( addr < 0 )617 {618 a = (uint8_t) nz;619 goto inc_pc_loop;620 }621 WRITE( 0, addr, /*(uint8_t)*/ nz );622 goto inc_pc_loop;623 }625 }627 // 6. ADDITION & SUBTRACTION COMMANDS629 #define INC_DEC_REG( reg, op )\630 nz = reg op;\631 reg = (uint8_t) nz;\632 goto loop;634 case 0xBC: INC_DEC_REG( a, + 1 ) // INC A635 case 0x3D: INC_DEC_REG( x, + 1 ) // INC X636 case 0xFC: INC_DEC_REG( y, + 1 ) // INC Y638 case 0x9C: INC_DEC_REG( a, - 1 ) // DEC A639 case 0x1D: INC_DEC_REG( x, - 1 ) // DEC X640 case 0xDC: INC_DEC_REG( y, - 1 ) // DEC Y642 case 0x9B: // DEC dp+X643 case 0xBB: // INC dp+X644 data = (uint8_t) (data + x);645 case 0x8B: // DEC dp646 case 0xAB: // INC dp647 data += dp;648 goto inc_abs;649 case 0x8C: // DEC abs650 case 0xAC: // INC abs651 data = READ_PC16( pc );652 pc++;653 inc_abs:654 nz = (opcode >> 4 & 2) - 1;655 nz += READ( -1, data );656 WRITE( 0, data, /*(uint8_t)*/ nz );657 goto inc_pc_loop;659 // 7. SHIFT, ROTATION COMMANDS661 case 0x5C: // LSR A662 c = 0;663 case 0x7C:{// ROR A664 nz = (c >> 1 & 0x80) | (a >> 1);665 c = a << 8;666 a = nz;667 goto loop;668 }670 case 0x1C: // ASL A671 c = 0;672 case 0x3C:{// ROL A673 int temp = c >> 8 & 1;674 c = a << 1;675 nz = c | temp;676 a = (uint8_t) nz;677 goto loop;678 }680 case 0x0B: // ASL dp681 c = 0;682 data += dp;683 goto rol_mem;684 case 0x1B: // ASL dp+X685 c = 0;686 case 0x3B: // ROL dp+X687 data = (uint8_t) (data + x);688 case 0x2B: // ROL dp689 data += dp;690 goto rol_mem;691 case 0x0C: // ASL abs692 c = 0;693 case 0x2C: // ROL abs694 data = READ_PC16( pc );695 pc++;696 rol_mem:697 nz = c >> 8 & 1;698 nz |= (c = READ( -1, data ) << 1);699 WRITE( 0, data, /*(uint8_t)*/ nz );700 goto inc_pc_loop;702 case 0x4B: // LSR dp703 c = 0;704 data += dp;705 goto ror_mem;706 case 0x5B: // LSR dp+X707 c = 0;708 case 0x7B: // ROR dp+X709 data = (uint8_t) (data + x);710 case 0x6B: // ROR dp711 data += dp;712 goto ror_mem;713 case 0x4C: // LSR abs714 c = 0;715 case 0x6C: // ROR abs716 data = READ_PC16( pc );717 pc++;718 ror_mem: {719 int temp = READ( -1, data );720 nz = (c >> 1 & 0x80) | (temp >> 1);721 c = temp << 8;722 WRITE( 0, data, nz );723 goto inc_pc_loop;724 }726 case 0x9F: // XCN727 nz = a = (a >> 4) | (uint8_t) (a << 4);728 goto loop;730 // 8. 16-BIT TRANSMISION COMMANDS732 case 0xBA: // MOVW YA,dp733 a = READ_DP( -2, data );734 nz = (a & 0x7F) | (a >> 1);735 y = READ_DP( 0, (uint8_t) (data + 1) );736 nz |= y;737 goto inc_pc_loop;739 case 0xDA: // MOVW dp,YA740 WRITE_DP( -1, data, a );741 WRITE_DP( 0, (uint8_t) (data + 1), y + no_read_before_write );742 goto inc_pc_loop;744 // 9. 16-BIT OPERATION COMMANDS746 case 0x3A: // INCW dp747 case 0x1A:{// DECW dp748 int temp;749 // low byte750 data += dp;751 temp = READ( -3, data );752 temp += (opcode >> 4 & 2) - 1; // +1 for INCW, -1 for DECW753 nz = ((temp >> 1) | temp) & 0x7F;754 WRITE( -2, data, /*(uint8_t)*/ temp );756 // high byte757 data = (uint8_t) (data + 1) + dp;758 temp = (uint8_t) ((temp >> 8) + READ( -1, data ));759 nz |= temp;760 WRITE( 0, data, temp );762 goto inc_pc_loop;763 }765 case 0x7A: // ADDW YA,dp766 case 0x9A:{// SUBW YA,dp767 int lo = READ_DP( -2, data );768 int hi = READ_DP( 0, (uint8_t) (data + 1) );769 int result;770 int flags;772 if ( opcode == 0x9A ) // SUBW773 {774 lo = (lo ^ 0xFF) + 1;775 hi ^= 0xFF;776 }778 lo += a;779 result = y + hi + (lo >> 8);780 flags = hi ^ y ^ result;782 psw = (psw & ~(v40 | h08)) |783 (flags >> 1 & h08) |784 ((flags + 0x80) >> 2 & v40);785 c = result;786 a = (uint8_t) lo;787 result = (uint8_t) result;788 y = result;789 nz = (((lo >> 1) | lo) & 0x7F) | result;791 goto inc_pc_loop;792 }794 case 0x5A: { // CMPW YA,dp795 int temp = a - READ_DP( -1, data );796 nz = ((temp >> 1) | temp) & 0x7F;797 temp = y + (temp >> 8);798 temp -= READ_DP( 0, (uint8_t) (data + 1) );799 nz |= temp;800 c = ~temp;801 nz &= 0xFF;802 goto inc_pc_loop;803 }805 // 10. MULTIPLICATION & DIVISON COMMANDS807 case 0xCF: { // MUL YA808 unsigned temp = y * a;809 a = (uint8_t) temp;810 nz = ((temp >> 1) | temp) & 0x7F;811 y = temp >> 8;812 nz |= y;813 goto loop;814 }816 case 0x9E: // DIV YA,X817 {818 unsigned ya = y * 0x100 + a;820 psw &= ~(h08 | v40);822 if ( y >= x )823 psw |= v40;825 if ( (y & 15) >= (x & 15) )826 psw |= h08;828 if ( y < x * 2 )829 {830 a = ya / x;831 y = ya - a * x;832 }833 else834 {835 a = 255 - (ya - x * 0x200) / (256 - x);836 y = x + (ya - x * 0x200) % (256 - x);837 }839 nz = (uint8_t) a;840 a = (uint8_t) a;842 goto loop;843 }845 // 11. DECIMAL COMPENSATION COMMANDS847 case 0xDF: // DAA848 SUSPICIOUS_OPCODE( "DAA" );849 if ( a > 0x99 || c & 0x100 )850 {851 a += 0x60;852 c = 0x100;853 }855 if ( (a & 0x0F) > 9 || psw & h08 )856 a += 0x06;858 nz = a;859 a = (uint8_t) a;860 goto loop;862 case 0xBE: // DAS863 SUSPICIOUS_OPCODE( "DAS" );864 if ( a > 0x99 || !(c & 0x100) )865 {866 a -= 0x60;867 c = 0;868 }870 if ( (a & 0x0F) > 9 || !(psw & h08) )871 a -= 0x06;873 nz = a;874 a = (uint8_t) a;875 goto loop;877 // 12. BRANCHING COMMANDS879 case 0x2F: // BRA rel880 pc += (BOOST::int8_t) data;881 goto inc_pc_loop;883 case 0x30: // BMI884 BRANCH( (nz & nz_neg_mask) )886 case 0x10: // BPL887 BRANCH( !(nz & nz_neg_mask) )889 case 0xB0: // BCS890 BRANCH( c & 0x100 )892 case 0x90: // BCC893 BRANCH( !(c & 0x100) )895 case 0x70: // BVS896 BRANCH( psw & v40 )898 case 0x50: // BVC899 BRANCH( !(psw & v40) )901 #define CBRANCH( cond )\902 {\903 pc++;\904 if ( cond )\905 goto cbranch_taken_loop;\906 rel_time -= 2;\907 goto inc_pc_loop;\908 }910 case 0x03: // BBS dp.bit,rel911 case 0x23:912 case 0x43:913 case 0x63:914 case 0x83:915 case 0xA3:916 case 0xC3:917 case 0xE3:918 CBRANCH( READ_DP( -4, data ) >> (opcode >> 5) & 1 )920 case 0x13: // BBC dp.bit,rel921 case 0x33:922 case 0x53:923 case 0x73:924 case 0x93:925 case 0xB3:926 case 0xD3:927 case 0xF3:928 CBRANCH( !(READ_DP( -4, data ) >> (opcode >> 5) & 1) )930 case 0xDE: // CBNE dp+X,rel931 data = (uint8_t) (data + x);932 // fall through933 case 0x2E:{// CBNE dp,rel934 int temp;935 // 61% from timer936 READ_DP_TIMER( -4, data, temp );937 CBRANCH( temp != a )938 }940 case 0x6E: { // DBNZ dp,rel941 unsigned temp = READ_DP( -4, data ) - 1;942 WRITE_DP( -3, (uint8_t) data, /*(uint8_t)*/ temp + no_read_before_write );943 CBRANCH( temp )944 }946 case 0xFE: // DBNZ Y,rel947 y = (uint8_t) (y - 1);948 BRANCH( y )950 case 0x1F: // JMP [abs+X]951 SET_PC( READ_PC16( pc ) + x );952 // fall through953 case 0x5F: // JMP abs954 SET_PC( READ_PC16( pc ) );955 goto loop;957 // 13. SUB-ROUTINE CALL RETURN COMMANDS959 case 0x0F:{// BRK960 int temp;961 int ret_addr = GET_PC();962 SUSPICIOUS_OPCODE( "BRK" );963 SET_PC( READ_PROG16( 0xFFDE ) ); // vector address verified964 PUSH16( ret_addr );965 GET_PSW( temp );966 psw = (psw | b10) & ~i04;967 PUSH( temp );968 goto loop;969 }971 case 0x4F:{// PCALL offset972 int ret_addr = GET_PC() + 1;973 SET_PC( 0xFF00 | data );974 PUSH16( ret_addr );975 goto loop;976 }978 case 0x01: // TCALL n979 case 0x11:980 case 0x21:981 case 0x31:982 case 0x41:983 case 0x51:984 case 0x61:985 case 0x71:986 case 0x81:987 case 0x91:988 case 0xA1:989 case 0xB1:990 case 0xC1:991 case 0xD1:992 case 0xE1:993 case 0xF1: {994 int ret_addr = GET_PC();995 SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) );996 PUSH16( ret_addr );997 goto loop;998 }1000 // 14. STACK OPERATION COMMANDS1002 {1003 int temp;1004 case 0x7F: // RET11005 temp = *sp;1006 SET_PC( GET_LE16( sp + 1 ) );1007 sp += 3;1008 goto set_psw;1009 case 0x8E: // POP PSW1010 POP( temp );1011 set_psw:1012 SET_PSW( temp );1013 goto loop;1014 }1016 case 0x0D: { // PUSH PSW1017 int temp;1018 GET_PSW( temp );1019 PUSH( temp );1020 goto loop;1021 }1023 case 0x2D: // PUSH A1024 PUSH( a );1025 goto loop;1027 case 0x4D: // PUSH X1028 PUSH( x );1029 goto loop;1031 case 0x6D: // PUSH Y1032 PUSH( y );1033 goto loop;1035 case 0xAE: // POP A1036 POP( a );1037 goto loop;1039 case 0xCE: // POP X1040 POP( x );1041 goto loop;1043 case 0xEE: // POP Y1044 POP( y );1045 goto loop;1047 // 15. BIT OPERATION COMMANDS1049 case 0x02: // SET11050 case 0x22:1051 case 0x42:1052 case 0x62:1053 case 0x82:1054 case 0xA2:1055 case 0xC2:1056 case 0xE2:1057 case 0x12: // CLR11058 case 0x32:1059 case 0x52:1060 case 0x72:1061 case 0x92:1062 case 0xB2:1063 case 0xD2:1064 case 0xF2: {1065 int bit = 1 << (opcode >> 5);1066 int mask = ~bit;1067 if ( opcode & 0x10 )1068 bit = 0;1069 data += dp;1070 WRITE( 0, data, (READ( -1, data ) & mask) | bit );1071 goto inc_pc_loop;1072 }1074 case 0x0E: // TSET1 abs1075 case 0x4E: // TCLR1 abs1076 data = READ_PC16( pc );1077 pc += 2;1078 {1079 unsigned temp = READ( -2, data );1080 nz = (uint8_t) (a - temp);1081 temp &= ~a;1082 if ( opcode == 0x0E )1083 temp |= a;1084 WRITE( 0, data, temp );1085 }1086 goto loop;1088 case 0x4A: // AND1 C,mem.bit1089 c &= MEM_BIT( 0 );1090 pc += 2;1091 goto loop;1093 case 0x6A: // AND1 C,/mem.bit1094 c &= ~MEM_BIT( 0 );1095 pc += 2;1096 goto loop;1098 case 0x0A: // OR1 C,mem.bit1099 c |= MEM_BIT( -1 );1100 pc += 2;1101 goto loop;1103 case 0x2A: // OR1 C,/mem.bit1104 c |= ~MEM_BIT( -1 );1105 pc += 2;1106 goto loop;1108 case 0x8A: // EOR1 C,mem.bit1109 c ^= MEM_BIT( -1 );1110 pc += 2;1111 goto loop;1113 case 0xEA: // NOT1 mem.bit1114 data = READ_PC16( pc );1115 pc += 2;1116 {1117 unsigned temp = READ( -1, data & 0x1FFF );1118 temp ^= 1 << (data >> 13);1119 WRITE( 0, data & 0x1FFF, temp );1120 }1121 goto loop;1123 case 0xCA: // MOV1 mem.bit,C1124 data = READ_PC16( pc );1125 pc += 2;1126 {1127 unsigned temp = READ( -2, data & 0x1FFF );1128 unsigned bit = data >> 13;1129 temp = (temp & ~(1 << bit)) | ((c >> 8 & 1) << bit);1130 WRITE( 0, data & 0x1FFF, temp + no_read_before_write );1131 }1132 goto loop;1134 case 0xAA: // MOV1 C,mem.bit1135 c = MEM_BIT( 0 );1136 pc += 2;1137 goto loop;1139 // 16. PROGRAM PSW FLAG OPERATION COMMANDS1141 case 0x60: // CLRC1142 c = 0;1143 goto loop;1145 case 0x80: // SETC1146 c = ~0;1147 goto loop;1149 case 0xED: // NOTC1150 c ^= 0x100;1151 goto loop;1153 case 0xE0: // CLRV1154 psw &= ~(v40 | h08);1155 goto loop;1157 case 0x20: // CLRP1158 dp = 0;1159 goto loop;1161 case 0x40: // SETP1162 dp = 0x100;1163 goto loop;1165 case 0xA0: // EI1166 SUSPICIOUS_OPCODE( "EI" );1167 psw |= i04;1168 goto loop;1170 case 0xC0: // DI1171 SUSPICIOUS_OPCODE( "DI" );1172 psw &= ~i04;1173 goto loop;1175 // 17. OTHER COMMANDS1177 case 0x00: // NOP1178 goto loop;1180 case 0xFF:{// STOP1181 // handle PC wrap-around1182 unsigned addr = GET_PC() - 1;1183 if ( addr >= 0x10000 )1184 {1185 addr &= 0xFFFF;1186 SET_PC( addr );1187 dprintf( "SPC: PC wrapped around\n" );1188 goto loop;1189 }1190 }1191 // fall through1192 case 0xEF: // SLEEP1193 SUSPICIOUS_OPCODE( "STOP/SLEEP" );1194 --pc;1195 rel_time = 0;1196 m.cpu_error = "SPC emulation error";1197 goto stop;1198 } // switch1200 assert( 0 ); // catch any unhandled instructions1201 }1202 out_of_time:1203 rel_time -= m.cycle_table [*pc]; // undo partial execution of opcode1204 stop:1206 // Uncache registers1207 if ( GET_PC() >= 0x10000 )1208 dprintf( "SPC: PC wrapped around\n" );1209 m.cpu_regs.pc = (uint16_t) GET_PC();1210 m.cpu_regs.sp = ( uint8_t) GET_SP();1211 m.cpu_regs.a = ( uint8_t) a;1212 m.cpu_regs.x = ( uint8_t) x;1213 m.cpu_regs.y = ( uint8_t) y;1214 {1215 int temp;1216 GET_PSW( temp );1217 m.cpu_regs.psw = (uint8_t) temp;1218 }1219 }1220 SPC_CPU_RUN_FUNC_END