summaryrefslogtreecommitdiff
path: root/plugins/gme/game-music-emu-0.5.5/gme/Spc_Cpu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/gme/game-music-emu-0.5.5/gme/Spc_Cpu.cpp')
-rw-r--r--plugins/gme/game-music-emu-0.5.5/gme/Spc_Cpu.cpp1062
1 files changed, 0 insertions, 1062 deletions
diff --git a/plugins/gme/game-music-emu-0.5.5/gme/Spc_Cpu.cpp b/plugins/gme/game-music-emu-0.5.5/gme/Spc_Cpu.cpp
deleted file mode 100644
index 8b61a455..00000000
--- a/plugins/gme/game-music-emu-0.5.5/gme/Spc_Cpu.cpp
+++ /dev/null
@@ -1,1062 +0,0 @@
-// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/
-
-#include "Spc_Cpu.h"
-
-#include "blargg_endian.h"
-#include "Snes_Spc.h"
-
-/* Copyright (C) 2004-2006 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 */
-
-#include "blargg_source.h"
-
-// Several instructions are commented out (or not even implemented). These aren't
-// used by the SPC files tested.
-
-// Optimize performance for the most common instructions, and size for the rest:
-//
-// 15% 0xF0 BEQ rel
-// 8% 0xE4 MOV A,dp
-// 4% 0xF5 MOV A,abs+X
-// 4% 0xD0 BNE rel
-// 4% 0x6F RET
-// 4% 0x3F CALL addr
-// 4% 0xF4 MOV A,dp+X
-// 3% 0xC4 MOV dp,A
-// 2% 0xEB MOV Y,dp
-// 2% 0x3D INC X
-// 2% 0xF6 MOV A,abs+Y
-// (1% and below not shown)
-
-Spc_Cpu::Spc_Cpu( Snes_Spc* e, uint8_t* ram_in ) : ram( ram_in ), emu( *e )
-{
- remain_ = 0;
- assert( INT_MAX >= 0x7FFFFFFF ); // requires 32-bit int
- blargg_verify_byte_order();
-}
-
-#define READ( addr ) (emu.read( addr ))
-#define WRITE( addr, value ) (emu.write( addr, value ))
-
-#define READ_DP( addr ) READ( (addr) + dp )
-#define WRITE_DP( addr, value ) WRITE( (addr) + dp, value )
-
-#define READ_PROG( addr ) (ram [addr])
-#define READ_PROG16( addr ) GET_LE16( &READ_PROG( addr ) )
-
-int Spc_Cpu::read( spc_addr_t addr )
-{
- return READ( addr );
-}
-
-void Spc_Cpu::write( spc_addr_t addr, int data )
-{
- WRITE( addr, data );
-}
-
-// Cycle table derived from text copy of SPC-700 manual (using regular expressions)
-static unsigned char const cycle_table [0x100] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 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
-};
-
-// The C,mem instructions are hardly used, so a non-inline function is used for
-// the common access code.
-unsigned Spc_Cpu::mem_bit( spc_addr_t pc )
-{
- unsigned addr = READ_PROG16( pc );
- unsigned t = READ( addr & 0x1FFF ) >> (addr >> 13);
- return (t << 8) & 0x100;
-}
-
-spc_time_t Spc_Cpu::run( spc_time_t cycle_count )
-{
- remain_ = cycle_count;
-
- uint8_t* const ram = this->ram; // cache
-
- // Stack pointer is kept one greater than usual SPC stack pointer to allow
- // common pre-decrement and post-increment memory instructions that some
- // processors have. Address wrap-around isn't supported.
- #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)
-
- uint8_t* sp;
- SET_SP( r.sp );
-
- // registers
- unsigned pc = (unsigned) r.pc;
- int a = r.a;
- int x = r.x;
- int y = r.y;
-
- // status flags
-
- const int st_n = 0x80;
- const int st_v = 0x40;
- const int st_p = 0x20;
- const int st_b = 0x10;
- const int st_h = 0x08;
- const int st_i = 0x04;
- const int st_z = 0x02;
- const int st_c = 0x01;
-
- #define IS_NEG (nz & 0x880)
-
- #define CALC_STATUS( out ) do {\
- 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;\
- } while ( 0 )
-
- #define SET_STATUS( in ) do {\
- status = in & ~(st_n | st_z | st_c | st_p);\
- c = in << 8;\
- nz = (in << 4) & 0x800;\
- nz |= ~in & st_z;\
- dp = (in << 3) & 0x100;\
- } while ( 0 )
-
- int status;
- int c; // store C as 'c' & 0x100.
- int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x880) != 0
- unsigned dp; // direct page base
- {
- int temp = r.status;
- SET_STATUS( temp );
- }
-
- goto loop;
-
- unsigned data; // first operand of instruction and temporary across function calls
-
- // Common endings for instructions
-cbranch_taken_loop: // compare and branch
- pc += (BOOST::int8_t) READ_PROG( pc );
- remain_ -= 2;
-inc_pc_loop: // end of instruction with an operand
- pc++;
-loop:
-
- check( (unsigned) pc < 0x10000 );
- check( (unsigned) GET_SP() < 0x100 );
-
- check( (unsigned) a < 0x100 );
- check( (unsigned) x < 0x100 );
- check( (unsigned) y < 0x100 );
-
- unsigned opcode = READ_PROG( pc );
- pc++;
- // to do: if pc is at end of memory, this will get wrong byte
- data = READ_PROG( pc );
-
- if ( remain_ <= 0 )
- goto stop;
-
- remain_ -= cycle_table [opcode];
-
- // Use 'data' for temporaries whose lifetime crosses read/write calls, otherwise
- // use a local temporary.
- switch ( opcode )
- {
-
- #define BRANCH( cond ) {\
- pc++;\
- int offset = (BOOST::int8_t) data;\
- if ( cond ) {\
- pc += offset;\
- remain_ -= 2;\
- }\
- goto loop;\
- }
-
-// Most-Common
-
- case 0xF0: // BEQ (most common)
- BRANCH( !(uint8_t) nz )
-
- case 0xD0: // BNE
- BRANCH( (uint8_t) nz )
-
- case 0x3F: // CALL
- PUSH16( pc + 2 );
- pc = READ_PROG16( pc );
- goto loop;
-
- case 0x6F: // RET
- 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:\
- pc++;\
- data += 0x100 * READ_PROG( 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_PROG16( 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_PROG16( 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_PROG16( 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
- pc++;
- WRITE_DP( READ_PROG( 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*/\
- pc++;\
- addr = READ_PROG( 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
- pc++;
- nz = READ_DP( READ_PROG( 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_PROG16( 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_PROG16( 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
- pc++;
- addr = READ_PROG( 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 + (BOOST::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_PROG16( 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_PROG16( 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_PROG16( 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 += (BOOST::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)
- pc = READ_PROG16( pc ) + x;
- // fall through
- case 0x5F: // JMP abs
- pc = READ_PROG16( pc );
- goto loop;
-
-// 13. SUB-ROUTINE CALL RETURN COMMANDS
-
- case 0x0F:{// BRK
- check( false ); // untested
- PUSH16( pc + 1 );
- 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
- pc++;
- PUSH16( pc );
- 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( pc );
- pc = READ_PROG16( 0xFFDE - (opcode >> 3) );
- goto loop;
-
-// 14. STACK OPERATION COMMANDS
-
- {
- int temp;
- case 0x7F: // RET1
- temp = POP();
- 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_PROG16( 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 );
- pc += 2;
- goto loop;
-
- case 0x6A: // AND1 C,/mem.bit
- check( false ); // untested
- c &= ~mem_bit( pc );
- pc += 2;
- goto loop;
-
- case 0x0A: // OR1 C,mem.bit
- check( false ); // untested
- c |= mem_bit( pc );
- pc += 2;
- goto loop;
-
- case 0x2A: // OR1 C,/mem.bit
- check( false ); // untested
- c |= ~mem_bit( pc );
- pc += 2;
- goto loop;
-
- case 0x8A: // EOR1 C,mem.bit
- c ^= mem_bit( pc );
- pc += 2;
- goto loop;
-
- case 0xEA: { // NOT1 mem.bit
- data = READ_PROG16( 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_PROG16( 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 );
- 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( false ); // untested
- status |= st_i;
- goto loop;
-
- case 0xC0: // DI
- check( false ); // untested
- status &= ~st_i;
- goto loop;
-
-// 17. OTHER COMMANDS
-
- case 0x00: // NOP
- goto loop;
-
- //case 0xEF: // SLEEP
- //case 0xFF: // STOP
-
- } // switch
-
- // unhandled instructions fall out of switch so emulator can catch them
-
-stop:
- pc--;
-
- {
- int temp;
- CALC_STATUS( temp );
- r.status = (uint8_t) temp;
- }
-
- r.pc = pc;
- r.sp = (uint8_t) GET_SP();
- r.a = (uint8_t) a;
- r.x = (uint8_t) x;
- r.y = (uint8_t) y;
-
- return remain_;
-}